drm fixes for 5.10-rc7

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
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJfyZorAAoJEAx081l5xIa+inUP/2HXHXeYTUn0dW26GEMM/2XR
 buPNs2f7YmV+dVh2Eb1zM22guTmE8INmVZtaUBlN2L/lmh2kAJqZKn5QU1QTFbmH
 XY7ASKh9HURid8nBt+ZSopRXRKZkjiU/0ii98/1vxmjIGm4hTNVcm4BN82Ed94QK
 KgSYQbqH6gpkwk71Qe9xJhv9d1ySQP/Ubq6+p9qrb8/Cq0xvgLhYjl7bJ4MGzZ3/
 o3ILxnudSFQhDGwU1FxZiHZHjU1iuIZIEC7NauAjppNE1nv8T6JLIXjfRkCnRVWU
 rYMExK3HzZEFiHJU9ebYj3loTjn3PLEhNdy7zs5jRO5pgAkSlf0UM1GIeXe0LwSz
 wxqjrCE22rBlcPJCoXS0JXvFA4O00NbzPSRdQiPdQnMC28rESnTDxUW5vo0KI/tf
 XL63v7q8JHq5wel+8jD9ahBqfMLnXN9AnNzvZDQydYJz5Px2tsryIOaPsELvz/8M
 33iiH8iGfgLYn9fJWMuU7neE+PHsKB+4TsrTMYnOt9Lm1kRRJhpedoWZuyiMmE8Y
 skfj+5XTBceQz5bPr/IjSxiBJtGydpz7GfAkJc1nTgkeZDVT7JSYHQHNLxkylh/v
 SV/6Bu/NwdovCEgjFf3/DIkc13ymom2YgDd+NQFuqJ+nNe0quHThUKUtTE+jFHPr
 Yx6fEUwxn+GaujOfAjFQ
 =uZ33
 -----END PGP SIGNATURE-----

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()
  ...
This commit is contained in:
Linus Torvalds 2020-12-04 09:25:22 -08:00
commit e87297fa08
20 changed files with 233 additions and 185 deletions

View file

@ -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); tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_CNTL, tmp); 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 */ /* set the write pointer delay */
WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_WPTR_CNTL, 0); 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, WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_WPTR,
lower_32_bits(ring->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; 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,
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 */ /* Restore */
ring = &adev->vcn.inst[inst_idx].ring_enc[0]; 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_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_BASE_HI, upper_32_bits(ring->gpu_addr));
WREG32_SOC15(VCN, inst_idx, mmUVD_RB_SIZE, ring->ring_size / 4); 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)); WREG32_SOC15(VCN, inst_idx, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
ring = &adev->vcn.inst[inst_idx].ring_enc[1]; 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_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_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_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_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_RB_WPTR2, lower_32_bits(ring->wptr));
WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_WPTR, /* Unstall DPG */
RREG32_SOC15(VCN, inst_idx, mmUVD_SCRATCH2) & 0x7FFFFFFF); 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, SOC15_WAIT_ON_RREG(VCN, inst_idx, mmUVD_POWER_STATUS,
UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON, UVD_POWER_STATUS__UVD_POWER_STATUS_MASK); 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; 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) { if (ring->use_doorbell) {
adev->wb.wb[ring->wptr_offs] = lower_32_bits(ring->wptr); adev->wb.wb[ring->wptr_offs] = lower_32_bits(ring->wptr);
WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr)); WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr));

View file

@ -163,8 +163,17 @@ void rn_update_clocks(struct clk_mgr *clk_mgr_base,
new_clocks->dppclk_khz = 100000; 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; dpp_clock_lowered = true;
clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz; clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
update_dppclk = true; update_dppclk = true;

View file

@ -1164,7 +1164,12 @@ int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu,
if (ret) if (ret)
return 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); tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
WREG32_SOC15(THM, 0, mmCG_TACH_CTRL, WREG32_SOC15(THM, 0, mmCG_TACH_CTRL,
REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL), REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL),

View file

@ -18021,16 +18021,6 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915)
if (!HAS_GMCH(i915)) if (!HAS_GMCH(i915))
sanitize_watermarks(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; return 0;
} }
@ -18039,11 +18029,21 @@ int intel_modeset_init(struct drm_i915_private *i915)
{ {
int ret; int ret;
intel_overlay_setup(i915);
if (!HAS_DISPLAY(i915)) if (!HAS_DISPLAY(i915))
return 0; 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); ret = intel_fbdev_init(&i915->drm);
if (ret) if (ret)
return ret; return ret;

View file

@ -101,18 +101,37 @@ static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
intel_gt_pm_put_async(b->irq_engine->gt); 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, static void add_signaling_context(struct intel_breadcrumbs *b,
struct intel_context *ce) struct intel_context *ce)
{ {
intel_context_get(ce); lockdep_assert_held(&ce->signal_lock);
list_add_tail(&ce->signal_link, &b->signalers);
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) struct intel_context *ce)
{ {
list_del(&ce->signal_link); lockdep_assert_held(&ce->signal_lock);
intel_context_put(ce);
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) 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) 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)) { if (!__dma_fence_signal(&rq->fence)) {
i915_request_put(rq); i915_request_put(rq);
return false; 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); struct intel_breadcrumbs *b = container_of(work, typeof(*b), irq_work);
const ktime_t timestamp = ktime_get(); const ktime_t timestamp = ktime_get();
struct llist_node *signal, *sn; struct llist_node *signal, *sn;
struct intel_context *ce, *cn; struct intel_context *ce;
struct list_head *pos, *next;
signal = NULL; signal = NULL;
if (unlikely(!llist_empty(&b->signaled_requests))) if (unlikely(!llist_empty(&b->signaled_requests)))
signal = llist_del_all(&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. * 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 * interrupt draw less ire from other users of the system and tools
* like powertop. * like powertop.
*/ */
if (!signal && b->irq_armed && list_empty(&b->signalers)) if (!signal && READ_ONCE(b->irq_armed) && list_empty(&b->signalers))
__intel_breadcrumbs_disarm_irq(b); intel_breadcrumbs_disarm_irq(b);
list_for_each_entry_safe(ce, cn, &b->signalers, signal_link) { rcu_read_lock();
GEM_BUG_ON(list_empty(&ce->signals)); list_for_each_entry_rcu(ce, &b->signalers, signal_link) {
struct i915_request *rq;
list_for_each_safe(pos, next, &ce->signals) { list_for_each_entry_rcu(rq, &ce->signals, signal_link) {
struct i915_request *rq = bool release;
list_entry(pos, typeof(*rq), signal_link);
GEM_BUG_ON(!check_signal_order(ce, rq));
if (!__request_completed(rq)) if (!__request_completed(rq))
break; break;
if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL,
&rq->fence.flags))
break;
/* /*
* Queue for execution after dropping the signaling * Queue for execution after dropping the signaling
* spinlock as the callback chain may end up adding * spinlock as the callback chain may end up adding
* more signalers to the same context or engine. * 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)) if (__signal_request(rq))
/* We own signal_node now, xfer to local list */ /* We own signal_node now, xfer to local list */
signal = slist_add(&rq->signal_node, signal); signal = slist_add(&rq->signal_node, signal);
}
/* if (release) {
* 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 */
add_retire(b, ce->timeline); add_retire(b, ce->timeline);
remove_signaling_context(b, ce); intel_context_put(ce);
} }
} }
} }
rcu_read_unlock();
spin_unlock(&b->irq_lock);
llist_for_each_safe(signal, sn, signal) { llist_for_each_safe(signal, sn, signal) {
struct i915_request *rq = struct i915_request *rq =
@ -298,14 +313,15 @@ intel_breadcrumbs_create(struct intel_engine_cs *irq_engine)
if (!b) if (!b)
return NULL; 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_LIST_HEAD(&b->signalers);
init_llist_head(&b->signaled_requests); init_llist_head(&b->signaled_requests);
spin_lock_init(&b->irq_lock);
init_irq_work(&b->irq_work, signal_irq_work); init_irq_work(&b->irq_work, signal_irq_work);
b->irq_engine = irq_engine;
return b; return b;
} }
@ -347,9 +363,9 @@ void intel_breadcrumbs_free(struct intel_breadcrumbs *b)
kfree(b); kfree(b);
} }
static void insert_breadcrumb(struct i915_request *rq, static void insert_breadcrumb(struct i915_request *rq)
struct intel_breadcrumbs *b)
{ {
struct intel_breadcrumbs *b = READ_ONCE(rq->engine)->breadcrumbs;
struct intel_context *ce = rq->context; struct intel_context *ce = rq->context;
struct list_head *pos; struct list_head *pos;
@ -371,6 +387,7 @@ static void insert_breadcrumb(struct i915_request *rq,
} }
if (list_empty(&ce->signals)) { if (list_empty(&ce->signals)) {
intel_context_get(ce);
add_signaling_context(b, ce); add_signaling_context(b, ce);
pos = &ce->signals; pos = &ce->signals;
} else { } else {
@ -396,8 +413,9 @@ static void insert_breadcrumb(struct i915_request *rq,
break; 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(!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); 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) 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 */ /* Serialises with i915_request_retire() using rq->lock */
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags)) if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
@ -425,67 +443,30 @@ bool i915_request_enable_breadcrumb(struct i915_request *rq)
if (!test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags)) if (!test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags))
return true; return true;
/* spin_lock(&ce->signal_lock);
* 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().
*/
if (test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags)) if (test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags))
insert_breadcrumb(rq, b); insert_breadcrumb(rq);
spin_unlock(&ce->signal_lock);
spin_unlock(&b->irq_lock);
return true; return true;
} }
void i915_request_cancel_breadcrumb(struct i915_request *rq) void i915_request_cancel_breadcrumb(struct i915_request *rq)
{ {
struct intel_breadcrumbs *b = rq->engine->breadcrumbs; struct intel_context *ce = rq->context;
bool release;
/* if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags))
* We must wait for b->irq_lock so that we know the interrupt handler return;
* 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;
list_del(&rq->signal_link); spin_lock(&ce->signal_lock);
if (list_empty(&ce->signals)) list_del_rcu(&rq->signal_link);
remove_signaling_context(b, ce); 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);
i915_request_put(rq);
}
spin_unlock(&b->irq_lock);
} }
static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p) static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p)
@ -495,18 +476,17 @@ static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p)
drm_printf(p, "Signals:\n"); drm_printf(p, "Signals:\n");
spin_lock_irq(&b->irq_lock); rcu_read_lock();
list_for_each_entry(ce, &b->signalers, signal_link) { list_for_each_entry_rcu(ce, &b->signalers, signal_link) {
list_for_each_entry(rq, &ce->signals, signal_link) { list_for_each_entry_rcu(rq, &ce->signals, signal_link)
drm_printf(p, "\t[%llx:%llx%s] @ %dms\n", drm_printf(p, "\t[%llx:%llx%s] @ %dms\n",
rq->fence.context, rq->fence.seqno, rq->fence.context, rq->fence.seqno,
i915_request_completed(rq) ? "!" : i915_request_completed(rq) ? "!" :
i915_request_started(rq) ? "*" : i915_request_started(rq) ? "*" :
"", "",
jiffies_to_msecs(jiffies - rq->emitted_jiffies)); 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, void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,

View file

@ -29,18 +29,16 @@
* the overhead of waking that client is much preferred. * the overhead of waking that client is much preferred.
*/ */
struct intel_breadcrumbs { struct intel_breadcrumbs {
spinlock_t irq_lock; /* protects the lists used in hardirq context */
/* Not all breadcrumbs are attached to physical HW */ /* Not all breadcrumbs are attached to physical HW */
struct intel_engine_cs *irq_engine; struct intel_engine_cs *irq_engine;
spinlock_t signalers_lock; /* protects the list of signalers */
struct list_head signalers; struct list_head signalers;
struct llist_head signaled_requests; struct llist_head signaled_requests;
spinlock_t irq_lock; /* protects the interrupt from hardirq context */
struct irq_work irq_work; /* for use from inside irq_lock */ struct irq_work irq_work; /* for use from inside irq_lock */
unsigned int irq_enabled; unsigned int irq_enabled;
bool irq_armed; bool irq_armed;
}; };

View file

@ -25,9 +25,16 @@ static struct intel_context *intel_context_alloc(void)
return kmem_cache_zalloc(global.slab_ce, GFP_KERNEL); return kmem_cache_zalloc(global.slab_ce, GFP_KERNEL);
} }
static void rcu_context_free(struct rcu_head *rcu)
{
struct intel_context *ce = container_of(rcu, typeof(*ce), rcu);
kmem_cache_free(global.slab_ce, ce);
}
void intel_context_free(struct intel_context *ce) void intel_context_free(struct intel_context *ce)
{ {
kmem_cache_free(global.slab_ce, ce); call_rcu(&ce->rcu, rcu_context_free);
} }
struct intel_context * struct intel_context *
@ -356,8 +363,7 @@ static int __intel_context_active(struct i915_active *active)
} }
void void
intel_context_init(struct intel_context *ce, intel_context_init(struct intel_context *ce, struct intel_engine_cs *engine)
struct intel_engine_cs *engine)
{ {
GEM_BUG_ON(!engine->cops); GEM_BUG_ON(!engine->cops);
GEM_BUG_ON(!engine->gt->vm); GEM_BUG_ON(!engine->gt->vm);
@ -373,7 +379,8 @@ intel_context_init(struct intel_context *ce,
ce->vm = i915_vm_get(engine->gt->vm); ce->vm = i915_vm_get(engine->gt->vm);
INIT_LIST_HEAD(&ce->signal_link); /* NB ce->signal_link/lock is used under RCU */
spin_lock_init(&ce->signal_lock);
INIT_LIST_HEAD(&ce->signals); INIT_LIST_HEAD(&ce->signals);
mutex_init(&ce->pin_mutex); mutex_init(&ce->pin_mutex);

View file

@ -25,6 +25,7 @@ DECLARE_EWMA(runtime, 3, 8);
struct i915_gem_context; struct i915_gem_context;
struct i915_gem_ww_ctx; struct i915_gem_ww_ctx;
struct i915_vma; struct i915_vma;
struct intel_breadcrumbs;
struct intel_context; struct intel_context;
struct intel_ring; struct intel_ring;
@ -44,7 +45,16 @@ struct intel_context_ops {
}; };
struct intel_context { struct intel_context {
struct kref ref; /*
* Note: Some fields may be accessed under RCU.
*
* Unless otherwise noted a field can safely be assumed to be protected
* by strong reference counting.
*/
union {
struct kref ref; /* no kref_get_unless_zero()! */
struct rcu_head rcu;
};
struct intel_engine_cs *engine; struct intel_engine_cs *engine;
struct intel_engine_cs *inflight; struct intel_engine_cs *inflight;
@ -54,8 +64,15 @@ struct intel_context {
struct i915_address_space *vm; struct i915_address_space *vm;
struct i915_gem_context __rcu *gem_context; struct i915_gem_context __rcu *gem_context;
struct list_head signal_link; /*
struct list_head signals; * @signal_lock protects the list of requests that need signaling,
* @signals. While there are any requests that need signaling,
* we add the context to the breadcrumbs worker, and remove it
* upon completion/cancellation of the last request.
*/
struct list_head signal_link; /* Accessed under RCU */
struct list_head signals; /* Guarded by signal_lock */
spinlock_t signal_lock; /* protects signals, the list of requests */
struct i915_vma *state; struct i915_vma *state;
struct intel_ring *ring; struct intel_ring *ring;

View file

@ -131,7 +131,19 @@ static const struct drm_i915_mocs_entry skl_mocs_table[] = {
GEN9_MOCS_ENTRIES, GEN9_MOCS_ENTRIES,
MOCS_ENTRY(I915_MOCS_CACHED, MOCS_ENTRY(I915_MOCS_CACHED,
LE_3_WB | LE_TC_2_LLC_ELLC | LE_LRUM(3), LE_3_WB | LE_TC_2_LLC_ELLC | LE_LRUM(3),
L3_3_WB) L3_3_WB),
/*
* mocs:63
* - used by the L3 for all of its evictions.
* Thus it is expected to allow LLC cacheability to enable coherent
* flows to be maintained.
* - used to force L3 uncachable cycles.
* Thus it is expected to make the surface L3 uncacheable.
*/
MOCS_ENTRY(63,
LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
L3_1_UC)
}; };
/* NOTE: the LE_TGT_CACHE is not used on Broxton */ /* NOTE: the LE_TGT_CACHE is not used on Broxton */

View file

@ -883,6 +883,10 @@ void intel_rps_park(struct intel_rps *rps)
adj = -2; adj = -2;
rps->last_adj = adj; rps->last_adj = adj;
rps->cur_freq = max_t(int, rps->cur_freq + adj, rps->min_freq); rps->cur_freq = max_t(int, rps->cur_freq + adj, rps->min_freq);
if (rps->cur_freq < rps->efficient_freq) {
rps->cur_freq = rps->efficient_freq;
rps->last_adj = 0;
}
GT_TRACE(rps_to_gt(rps), "park:%x\n", rps->cur_freq); GT_TRACE(rps_to_gt(rps), "park:%x\n", rps->cur_freq);
} }

View file

@ -103,10 +103,13 @@ static int __shmem_rw(struct file *file, loff_t off,
return PTR_ERR(page); return PTR_ERR(page);
vaddr = kmap(page); vaddr = kmap(page);
if (write) if (write) {
memcpy(vaddr + offset_in_page(off), ptr, this); memcpy(vaddr + offset_in_page(off), ptr, this);
else set_page_dirty(page);
} else {
memcpy(ptr, vaddr + offset_in_page(off), this); memcpy(ptr, vaddr + offset_in_page(off), this);
}
mark_page_accessed(page);
kunmap(page); kunmap(page);
put_page(page); put_page(page);

View file

@ -177,10 +177,8 @@ struct i915_request {
struct intel_ring *ring; struct intel_ring *ring;
struct intel_timeline __rcu *timeline; struct intel_timeline __rcu *timeline;
union { struct list_head signal_link;
struct list_head signal_link; struct llist_node signal_node;
struct llist_node signal_node;
};
/* /*
* The rcu epoch of when this request was allocated. Used to judiciously * The rcu epoch of when this request was allocated. Used to judiciously

View file

@ -22,6 +22,7 @@
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_plane.h> #include <drm/drm_plane.h>
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include <drm/drm_vblank.h> #include <drm/drm_vblank.h>
@ -484,17 +485,27 @@ static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane,
writel(ctrl, mxsfb->base + LCDC_AS_CTRL); writel(ctrl, mxsfb->base + LCDC_AS_CTRL);
} }
static bool mxsfb_format_mod_supported(struct drm_plane *plane,
uint32_t format,
uint64_t modifier)
{
return modifier == DRM_FORMAT_MOD_LINEAR;
}
static const struct drm_plane_helper_funcs mxsfb_plane_primary_helper_funcs = { static const struct drm_plane_helper_funcs mxsfb_plane_primary_helper_funcs = {
.prepare_fb = drm_gem_fb_prepare_fb,
.atomic_check = mxsfb_plane_atomic_check, .atomic_check = mxsfb_plane_atomic_check,
.atomic_update = mxsfb_plane_primary_atomic_update, .atomic_update = mxsfb_plane_primary_atomic_update,
}; };
static const struct drm_plane_helper_funcs mxsfb_plane_overlay_helper_funcs = { static const struct drm_plane_helper_funcs mxsfb_plane_overlay_helper_funcs = {
.prepare_fb = drm_gem_fb_prepare_fb,
.atomic_check = mxsfb_plane_atomic_check, .atomic_check = mxsfb_plane_atomic_check,
.atomic_update = mxsfb_plane_overlay_atomic_update, .atomic_update = mxsfb_plane_overlay_atomic_update,
}; };
static const struct drm_plane_funcs mxsfb_plane_funcs = { static const struct drm_plane_funcs mxsfb_plane_funcs = {
.format_mod_supported = mxsfb_format_mod_supported,
.update_plane = drm_atomic_helper_update_plane, .update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane, .disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup, .destroy = drm_plane_cleanup,

View file

@ -1214,8 +1214,8 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg)
} }
reg->bus.offset = handle; reg->bus.offset = handle;
ret = 0;
} }
ret = 0;
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;

View file

@ -195,8 +195,7 @@ static void sdi_bridge_mode_set(struct drm_bridge *bridge,
sdi->pixelclock = adjusted_mode->clock * 1000; sdi->pixelclock = adjusted_mode->clock * 1000;
} }
static void sdi_bridge_enable(struct drm_bridge *bridge, static void sdi_bridge_enable(struct drm_bridge *bridge)
struct drm_bridge_state *bridge_state)
{ {
struct sdi_device *sdi = drm_bridge_to_sdi(bridge); struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
struct dispc_clock_info dispc_cinfo; struct dispc_clock_info dispc_cinfo;
@ -259,8 +258,7 @@ static void sdi_bridge_enable(struct drm_bridge *bridge,
regulator_disable(sdi->vdds_sdi_reg); regulator_disable(sdi->vdds_sdi_reg);
} }
static void sdi_bridge_disable(struct drm_bridge *bridge, static void sdi_bridge_disable(struct drm_bridge *bridge)
struct drm_bridge_state *bridge_state)
{ {
struct sdi_device *sdi = drm_bridge_to_sdi(bridge); struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
@ -278,8 +276,8 @@ static const struct drm_bridge_funcs sdi_bridge_funcs = {
.mode_valid = sdi_bridge_mode_valid, .mode_valid = sdi_bridge_mode_valid,
.mode_fixup = sdi_bridge_mode_fixup, .mode_fixup = sdi_bridge_mode_fixup,
.mode_set = sdi_bridge_mode_set, .mode_set = sdi_bridge_mode_set,
.atomic_enable = sdi_bridge_enable, .enable = sdi_bridge_enable,
.atomic_disable = sdi_bridge_disable, .disable = sdi_bridge_disable,
}; };
static void sdi_bridge_init(struct sdi_device *sdi) static void sdi_bridge_init(struct sdi_device *sdi)

View file

@ -629,7 +629,7 @@ static int acx565akm_probe(struct spi_device *spi)
lcd->spi = spi; lcd->spi = spi;
mutex_init(&lcd->mutex); mutex_init(&lcd->mutex);
lcd->reset_gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW); lcd->reset_gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(lcd->reset_gpio)) { if (IS_ERR(lcd->reset_gpio)) {
dev_err(&spi->dev, "failed to get reset GPIO\n"); dev_err(&spi->dev, "failed to get reset GPIO\n");
return PTR_ERR(lcd->reset_gpio); return PTR_ERR(lcd->reset_gpio);

View file

@ -544,7 +544,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
struct device_node *port, *endpoint; struct device_node *port, *endpoint;
int ret = 0, child_count = 0; int ret = 0, child_count = 0;
const char *name; const char *name;
u32 endpoint_id; u32 endpoint_id = 0;
lvds->drm_dev = drm_dev; lvds->drm_dev = drm_dev;
port = of_graph_get_port_by_id(dev->of_node, 1); port = of_graph_get_port_by_id(dev->of_node, 1);

View file

@ -90,7 +90,7 @@ static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
if (!fpriv) if (!fpriv)
return -ENOMEM; return -ENOMEM;
idr_init(&fpriv->contexts); idr_init_base(&fpriv->contexts, 1);
mutex_init(&fpriv->lock); mutex_init(&fpriv->lock);
filp->driver_priv = fpriv; filp->driver_priv = fpriv;

View file

@ -129,7 +129,6 @@ int tegra_output_probe(struct tegra_output *output)
if (!output->ddc) { if (!output->ddc) {
err = -EPROBE_DEFER; err = -EPROBE_DEFER;
of_node_put(ddc);
return err; return err;
} }
} }

View file

@ -397,7 +397,6 @@ struct tegra_sor;
struct tegra_sor_ops { struct tegra_sor_ops {
const char *name; const char *name;
int (*probe)(struct tegra_sor *sor); int (*probe)(struct tegra_sor *sor);
int (*remove)(struct tegra_sor *sor);
void (*audio_enable)(struct tegra_sor *sor); void (*audio_enable)(struct tegra_sor *sor);
void (*audio_disable)(struct tegra_sor *sor); void (*audio_disable)(struct tegra_sor *sor);
}; };
@ -2942,6 +2941,24 @@ static const struct drm_encoder_helper_funcs tegra_sor_dp_helpers = {
.atomic_check = tegra_sor_encoder_atomic_check, .atomic_check = tegra_sor_encoder_atomic_check,
}; };
static void tegra_sor_disable_regulator(void *data)
{
struct regulator *reg = data;
regulator_disable(reg);
}
static int tegra_sor_enable_regulator(struct tegra_sor *sor, struct regulator *reg)
{
int err;
err = regulator_enable(reg);
if (err)
return err;
return devm_add_action_or_reset(sor->dev, tegra_sor_disable_regulator, reg);
}
static int tegra_sor_hdmi_probe(struct tegra_sor *sor) static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
{ {
int err; int err;
@ -2953,7 +2970,7 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
return PTR_ERR(sor->avdd_io_supply); return PTR_ERR(sor->avdd_io_supply);
} }
err = regulator_enable(sor->avdd_io_supply); err = tegra_sor_enable_regulator(sor, sor->avdd_io_supply);
if (err < 0) { if (err < 0) {
dev_err(sor->dev, "failed to enable AVDD I/O supply: %d\n", dev_err(sor->dev, "failed to enable AVDD I/O supply: %d\n",
err); err);
@ -2967,7 +2984,7 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
return PTR_ERR(sor->vdd_pll_supply); return PTR_ERR(sor->vdd_pll_supply);
} }
err = regulator_enable(sor->vdd_pll_supply); err = tegra_sor_enable_regulator(sor, sor->vdd_pll_supply);
if (err < 0) { if (err < 0) {
dev_err(sor->dev, "failed to enable VDD PLL supply: %d\n", dev_err(sor->dev, "failed to enable VDD PLL supply: %d\n",
err); err);
@ -2981,7 +2998,7 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
return PTR_ERR(sor->hdmi_supply); return PTR_ERR(sor->hdmi_supply);
} }
err = regulator_enable(sor->hdmi_supply); err = tegra_sor_enable_regulator(sor, sor->hdmi_supply);
if (err < 0) { if (err < 0) {
dev_err(sor->dev, "failed to enable HDMI supply: %d\n", err); dev_err(sor->dev, "failed to enable HDMI supply: %d\n", err);
return err; return err;
@ -2992,19 +3009,9 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
return 0; return 0;
} }
static int tegra_sor_hdmi_remove(struct tegra_sor *sor)
{
regulator_disable(sor->hdmi_supply);
regulator_disable(sor->vdd_pll_supply);
regulator_disable(sor->avdd_io_supply);
return 0;
}
static const struct tegra_sor_ops tegra_sor_hdmi_ops = { static const struct tegra_sor_ops tegra_sor_hdmi_ops = {
.name = "HDMI", .name = "HDMI",
.probe = tegra_sor_hdmi_probe, .probe = tegra_sor_hdmi_probe,
.remove = tegra_sor_hdmi_remove,
.audio_enable = tegra_sor_hdmi_audio_enable, .audio_enable = tegra_sor_hdmi_audio_enable,
.audio_disable = tegra_sor_hdmi_audio_disable, .audio_disable = tegra_sor_hdmi_audio_disable,
}; };
@ -3017,7 +3024,7 @@ static int tegra_sor_dp_probe(struct tegra_sor *sor)
if (IS_ERR(sor->avdd_io_supply)) if (IS_ERR(sor->avdd_io_supply))
return PTR_ERR(sor->avdd_io_supply); return PTR_ERR(sor->avdd_io_supply);
err = regulator_enable(sor->avdd_io_supply); err = tegra_sor_enable_regulator(sor, sor->avdd_io_supply);
if (err < 0) if (err < 0)
return err; return err;
@ -3025,25 +3032,16 @@ static int tegra_sor_dp_probe(struct tegra_sor *sor)
if (IS_ERR(sor->vdd_pll_supply)) if (IS_ERR(sor->vdd_pll_supply))
return PTR_ERR(sor->vdd_pll_supply); return PTR_ERR(sor->vdd_pll_supply);
err = regulator_enable(sor->vdd_pll_supply); err = tegra_sor_enable_regulator(sor, sor->vdd_pll_supply);
if (err < 0) if (err < 0)
return err; return err;
return 0; return 0;
} }
static int tegra_sor_dp_remove(struct tegra_sor *sor)
{
regulator_disable(sor->vdd_pll_supply);
regulator_disable(sor->avdd_io_supply);
return 0;
}
static const struct tegra_sor_ops tegra_sor_dp_ops = { static const struct tegra_sor_ops tegra_sor_dp_ops = {
.name = "DP", .name = "DP",
.probe = tegra_sor_dp_probe, .probe = tegra_sor_dp_probe,
.remove = tegra_sor_dp_remove,
}; };
static int tegra_sor_init(struct host1x_client *client) static int tegra_sor_init(struct host1x_client *client)
@ -3145,6 +3143,7 @@ static int tegra_sor_init(struct host1x_client *client)
if (err < 0) { if (err < 0) {
dev_err(sor->dev, "failed to deassert SOR reset: %d\n", dev_err(sor->dev, "failed to deassert SOR reset: %d\n",
err); err);
clk_disable_unprepare(sor->clk);
return err; return err;
} }
@ -3152,12 +3151,17 @@ static int tegra_sor_init(struct host1x_client *client)
} }
err = clk_prepare_enable(sor->clk_safe); err = clk_prepare_enable(sor->clk_safe);
if (err < 0) if (err < 0) {
clk_disable_unprepare(sor->clk);
return err; return err;
}
err = clk_prepare_enable(sor->clk_dp); err = clk_prepare_enable(sor->clk_dp);
if (err < 0) if (err < 0) {
clk_disable_unprepare(sor->clk_safe);
clk_disable_unprepare(sor->clk);
return err; return err;
}
return 0; return 0;
} }
@ -3764,17 +3768,16 @@ static int tegra_sor_probe(struct platform_device *pdev)
return err; return err;
err = tegra_output_probe(&sor->output); err = tegra_output_probe(&sor->output);
if (err < 0) { if (err < 0)
dev_err(&pdev->dev, "failed to probe output: %d\n", err); return dev_err_probe(&pdev->dev, err,
return err; "failed to probe output\n");
}
if (sor->ops && sor->ops->probe) { if (sor->ops && sor->ops->probe) {
err = sor->ops->probe(sor); err = sor->ops->probe(sor);
if (err < 0) { if (err < 0) {
dev_err(&pdev->dev, "failed to probe %s: %d\n", dev_err(&pdev->dev, "failed to probe %s: %d\n",
sor->ops->name, err); sor->ops->name, err);
goto output; goto remove;
} }
} }
@ -3955,9 +3958,6 @@ static int tegra_sor_probe(struct platform_device *pdev)
rpm_disable: rpm_disable:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
remove: remove:
if (sor->ops && sor->ops->remove)
sor->ops->remove(sor);
output:
tegra_output_remove(&sor->output); tegra_output_remove(&sor->output);
return err; return err;
} }
@ -3976,12 +3976,6 @@ static int tegra_sor_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
if (sor->ops && sor->ops->remove) {
err = sor->ops->remove(sor);
if (err < 0)
dev_err(&pdev->dev, "failed to remove SOR: %d\n", err);
}
tegra_output_remove(&sor->output); tegra_output_remove(&sor->output);
return 0; return 0;