Skip to content

Commit b7137e0

Browse files
committed
drm/i915: Defer enabling rc6 til after we submit the first batch/context
Some hardware requires a valid render context before it can initiate rc6 power gating of the GPU; the default state of the GPU is not sufficient and may lead to undefined behaviour. The first execution of any batch will load the "golden render state", at which point it is safe to enable rc6. As we do not forcibly load the kernel context at resume, we have to hook into the batch submission to be sure that the render state is setup before enabling rc6. However, since we don't enable powersaving until that first batch, we queued a delayed task in order to guarantee that the batch is indeed submitted. v2: Rearrange intel_disable_gt_powersave() to match. v3: Apply user specified cur_freq (or idle_freq if not set). v4: Give in, and supply a delayed work to autoenable rc6 v5: Mika suggested a couple of better names for delayed_resume_work v6: Rebalance rpm_put around the autoenable task Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1468397438-21226-7-git-send-email-chris@chris-wilson.co.uk Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com>
1 parent 62e1baa commit b7137e0

File tree

7 files changed

+94
-64
lines changed

7 files changed

+94
-64
lines changed

drivers/gpu/drm/i915/i915_drv.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,7 +1343,7 @@ void i915_driver_unload(struct drm_device *dev)
13431343
i915_destroy_error_state(dev);
13441344

13451345
/* Flush any outstanding unpin_work. */
1346-
flush_workqueue(dev_priv->wq);
1346+
drain_workqueue(dev_priv->wq);
13471347

13481348
intel_guc_fini(dev);
13491349
i915_gem_fini(dev);
@@ -1458,8 +1458,6 @@ static int i915_drm_suspend(struct drm_device *dev)
14581458

14591459
intel_guc_suspend(dev);
14601460

1461-
intel_suspend_gt_powersave(dev_priv);
1462-
14631461
intel_display_suspend(dev);
14641462

14651463
intel_dp_mst_suspend(dev);
@@ -1652,6 +1650,7 @@ static int i915_drm_resume(struct drm_device *dev)
16521650

16531651
intel_opregion_notify_adapter(dev_priv, PCI_D0);
16541652

1653+
intel_autoenable_gt_powersave(dev_priv);
16551654
drm_kms_helper_poll_enable(dev);
16561655

16571656
enable_rpm_wakeref_asserts(dev_priv);
@@ -1778,8 +1777,6 @@ int i915_reset(struct drm_i915_private *dev_priv)
17781777
unsigned reset_counter;
17791778
int ret;
17801779

1781-
intel_reset_gt_powersave(dev_priv);
1782-
17831780
mutex_lock(&dev->struct_mutex);
17841781

17851782
/* Clear any previous failed attempts at recovery. Time to try again. */
@@ -1835,8 +1832,7 @@ int i915_reset(struct drm_i915_private *dev_priv)
18351832
* previous concerns that it doesn't respond well to some forms
18361833
* of re-init after reset.
18371834
*/
1838-
if (INTEL_INFO(dev)->gen > 5)
1839-
intel_enable_gt_powersave(dev_priv);
1835+
intel_autoenable_gt_powersave(dev_priv);
18401836

18411837
return 0;
18421838

@@ -2459,7 +2455,6 @@ static int intel_runtime_resume(struct device *device)
24592455
* we can do is to hope that things will still work (and disable RPM).
24602456
*/
24612457
i915_gem_init_swizzling(dev);
2462-
gen6_update_ring_freq(dev_priv);
24632458

24642459
intel_runtime_pm_enable_interrupts(dev_priv);
24652460

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1188,7 +1188,7 @@ struct intel_gen6_power_mgmt {
11881188
bool client_boost;
11891189

11901190
bool enabled;
1191-
struct delayed_work delayed_resume_work;
1191+
struct delayed_work autoenable_work;
11921192
unsigned boosts;
11931193

11941194
struct intel_rps_client semaphores, mmioflips;

drivers/gpu/drm/i915/i915_gem.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2842,6 +2842,7 @@ static void i915_gem_mark_busy(const struct intel_engine_cs *engine)
28422842
intel_runtime_pm_get_noresume(dev_priv);
28432843
dev_priv->gt.awake = true;
28442844

2845+
intel_enable_gt_powersave(dev_priv);
28452846
i915_update_gfx_val(dev_priv);
28462847
if (INTEL_GEN(dev_priv) >= 6)
28472848
gen6_rps_busy(dev_priv);
@@ -4979,6 +4980,8 @@ i915_gem_suspend(struct drm_device *dev)
49794980
struct drm_i915_private *dev_priv = to_i915(dev);
49804981
int ret = 0;
49814982

4983+
intel_suspend_gt_powersave(dev_priv);
4984+
49824985
mutex_lock(&dev->struct_mutex);
49834986
ret = i915_gem_wait_for_idle(dev_priv);
49844987
if (ret)

drivers/gpu/drm/i915/intel_display.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15456,7 +15456,6 @@ void intel_modeset_init_hw(struct drm_device *dev)
1545615456
dev_priv->atomic_cdclk_freq = dev_priv->cdclk_freq;
1545715457

1545815458
intel_init_clock_gating(dev);
15459-
intel_enable_gt_powersave(dev_priv);
1546015459
}
1546115460

1546215461
/*

drivers/gpu/drm/i915/intel_drv.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1690,10 +1690,11 @@ void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
16901690
void intel_gpu_ips_teardown(void);
16911691
void intel_init_gt_powersave(struct drm_i915_private *dev_priv);
16921692
void intel_cleanup_gt_powersave(struct drm_i915_private *dev_priv);
1693+
void intel_sanitize_gt_powersave(struct drm_i915_private *dev_priv);
16931694
void intel_enable_gt_powersave(struct drm_i915_private *dev_priv);
1695+
void intel_autoenable_gt_powersave(struct drm_i915_private *dev_priv);
16941696
void intel_disable_gt_powersave(struct drm_i915_private *dev_priv);
16951697
void intel_suspend_gt_powersave(struct drm_i915_private *dev_priv);
1696-
void intel_reset_gt_powersave(struct drm_i915_private *dev_priv);
16971698
void gen6_update_ring_freq(struct drm_i915_private *dev_priv);
16981699
void gen6_rps_busy(struct drm_i915_private *dev_priv);
16991700
void gen6_rps_reset_ei(struct drm_i915_private *dev_priv);

drivers/gpu/drm/i915/intel_pm.c

Lines changed: 84 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6536,6 +6536,8 @@ void intel_init_gt_powersave(struct drm_i915_private *dev_priv)
65366536
dev_priv->rps.boost_freq = dev_priv->rps.max_freq;
65376537

65386538
mutex_unlock(&dev_priv->rps.hw_lock);
6539+
6540+
intel_autoenable_gt_powersave(dev_priv);
65396541
}
65406542

65416543
void intel_cleanup_gt_powersave(struct drm_i915_private *dev_priv)
@@ -6549,13 +6551,6 @@ void intel_cleanup_gt_powersave(struct drm_i915_private *dev_priv)
65496551
intel_runtime_pm_put(dev_priv);
65506552
}
65516553

6552-
static void gen6_suspend_rps(struct drm_i915_private *dev_priv)
6553-
{
6554-
flush_delayed_work(&dev_priv->rps.delayed_resume_work);
6555-
6556-
gen6_disable_rps_interrupts(dev_priv);
6557-
}
6558-
65596554
/**
65606555
* intel_suspend_gt_powersave - suspend PM work and helper threads
65616556
* @dev_priv: i915 device
@@ -6569,60 +6564,76 @@ void intel_suspend_gt_powersave(struct drm_i915_private *dev_priv)
65696564
if (INTEL_GEN(dev_priv) < 6)
65706565
return;
65716566

6572-
gen6_suspend_rps(dev_priv);
6567+
if (cancel_delayed_work_sync(&dev_priv->rps.autoenable_work))
6568+
intel_runtime_pm_put(dev_priv);
65736569

6574-
/* Force GPU to min freq during suspend */
6575-
gen6_rps_idle(dev_priv);
6570+
/* gen6_rps_idle() will be called later to disable interrupts */
6571+
}
6572+
6573+
void intel_sanitize_gt_powersave(struct drm_i915_private *dev_priv)
6574+
{
6575+
dev_priv->rps.enabled = true; /* force disabling */
6576+
intel_disable_gt_powersave(dev_priv);
6577+
6578+
gen6_reset_rps_interrupts(dev_priv);
65766579
}
65776580

65786581
void intel_disable_gt_powersave(struct drm_i915_private *dev_priv)
65796582
{
6580-
if (IS_IRONLAKE_M(dev_priv)) {
6581-
ironlake_disable_drps(dev_priv);
6582-
} else if (INTEL_INFO(dev_priv)->gen >= 6) {
6583-
intel_suspend_gt_powersave(dev_priv);
6583+
if (!READ_ONCE(dev_priv->rps.enabled))
6584+
return;
65846585

6585-
mutex_lock(&dev_priv->rps.hw_lock);
6586-
if (INTEL_INFO(dev_priv)->gen >= 9) {
6587-
gen9_disable_rc6(dev_priv);
6588-
gen9_disable_rps(dev_priv);
6589-
} else if (IS_CHERRYVIEW(dev_priv))
6590-
cherryview_disable_rps(dev_priv);
6591-
else if (IS_VALLEYVIEW(dev_priv))
6592-
valleyview_disable_rps(dev_priv);
6593-
else
6594-
gen6_disable_rps(dev_priv);
6586+
mutex_lock(&dev_priv->rps.hw_lock);
65956587

6596-
dev_priv->rps.enabled = false;
6597-
mutex_unlock(&dev_priv->rps.hw_lock);
6588+
if (INTEL_GEN(dev_priv) >= 9) {
6589+
gen9_disable_rc6(dev_priv);
6590+
gen9_disable_rps(dev_priv);
6591+
} else if (IS_CHERRYVIEW(dev_priv)) {
6592+
cherryview_disable_rps(dev_priv);
6593+
} else if (IS_VALLEYVIEW(dev_priv)) {
6594+
valleyview_disable_rps(dev_priv);
6595+
} else if (INTEL_GEN(dev_priv) >= 6) {
6596+
gen6_disable_rps(dev_priv);
6597+
} else if (IS_IRONLAKE_M(dev_priv)) {
6598+
ironlake_disable_drps(dev_priv);
65986599
}
6600+
6601+
dev_priv->rps.enabled = false;
6602+
mutex_unlock(&dev_priv->rps.hw_lock);
65996603
}
66006604

6601-
static void intel_gen6_powersave_work(struct work_struct *work)
6605+
void intel_enable_gt_powersave(struct drm_i915_private *dev_priv)
66026606
{
6603-
struct drm_i915_private *dev_priv =
6604-
container_of(work, struct drm_i915_private,
6605-
rps.delayed_resume_work.work);
6607+
/* We shouldn't be disabling as we submit, so this should be less
6608+
* racy than it appears!
6609+
*/
6610+
if (READ_ONCE(dev_priv->rps.enabled))
6611+
return;
66066612

6607-
mutex_lock(&dev_priv->rps.hw_lock);
6613+
/* Powersaving is controlled by the host when inside a VM */
6614+
if (intel_vgpu_active(dev_priv))
6615+
return;
66086616

6609-
gen6_reset_rps_interrupts(dev_priv);
6617+
mutex_lock(&dev_priv->rps.hw_lock);
66106618

66116619
if (IS_CHERRYVIEW(dev_priv)) {
66126620
cherryview_enable_rps(dev_priv);
66136621
} else if (IS_VALLEYVIEW(dev_priv)) {
66146622
valleyview_enable_rps(dev_priv);
6615-
} else if (INTEL_INFO(dev_priv)->gen >= 9) {
6623+
} else if (INTEL_GEN(dev_priv) >= 9) {
66166624
gen9_enable_rc6(dev_priv);
66176625
gen9_enable_rps(dev_priv);
66186626
if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
66196627
__gen6_update_ring_freq(dev_priv);
66206628
} else if (IS_BROADWELL(dev_priv)) {
66216629
gen8_enable_rps(dev_priv);
66226630
__gen6_update_ring_freq(dev_priv);
6623-
} else {
6631+
} else if (INTEL_GEN(dev_priv) >= 6) {
66246632
gen6_enable_rps(dev_priv);
66256633
__gen6_update_ring_freq(dev_priv);
6634+
} else if (IS_IRONLAKE_M(dev_priv)) {
6635+
ironlake_enable_drps(dev_priv);
6636+
intel_init_emon(dev_priv);
66266637
}
66276638

66286639
WARN_ON(dev_priv->rps.max_freq < dev_priv->rps.min_freq);
@@ -6632,18 +6643,47 @@ static void intel_gen6_powersave_work(struct work_struct *work)
66326643
WARN_ON(dev_priv->rps.efficient_freq > dev_priv->rps.max_freq);
66336644

66346645
dev_priv->rps.enabled = true;
6646+
mutex_unlock(&dev_priv->rps.hw_lock);
6647+
}
66356648

6636-
gen6_enable_rps_interrupts(dev_priv);
6649+
static void __intel_autoenable_gt_powersave(struct work_struct *work)
6650+
{
6651+
struct drm_i915_private *dev_priv =
6652+
container_of(work, typeof(*dev_priv), rps.autoenable_work.work);
6653+
struct intel_engine_cs *rcs;
6654+
struct drm_i915_gem_request *req;
66376655

6638-
mutex_unlock(&dev_priv->rps.hw_lock);
6656+
if (READ_ONCE(dev_priv->rps.enabled))
6657+
goto out;
6658+
6659+
rcs = &dev_priv->engine[RCS];
6660+
if (rcs->last_context)
6661+
goto out;
6662+
6663+
if (!rcs->init_context)
6664+
goto out;
66396665

6666+
mutex_lock(&dev_priv->drm.struct_mutex);
6667+
6668+
req = i915_gem_request_alloc(rcs, dev_priv->kernel_context);
6669+
if (IS_ERR(req))
6670+
goto unlock;
6671+
6672+
if (!i915.enable_execlists && i915_switch_context(req) == 0)
6673+
rcs->init_context(req);
6674+
6675+
/* Mark the device busy, calling intel_enable_gt_powersave() */
6676+
i915_add_request_no_flush(req);
6677+
6678+
unlock:
6679+
mutex_unlock(&dev_priv->drm.struct_mutex);
6680+
out:
66406681
intel_runtime_pm_put(dev_priv);
66416682
}
66426683

6643-
void intel_enable_gt_powersave(struct drm_i915_private *dev_priv)
6684+
void intel_autoenable_gt_powersave(struct drm_i915_private *dev_priv)
66446685
{
6645-
/* Powersaving is controlled by the host when inside a VM */
6646-
if (intel_vgpu_active(dev_priv))
6686+
if (READ_ONCE(dev_priv->rps.enabled))
66476687
return;
66486688

66496689
if (IS_IRONLAKE_M(dev_priv)) {
@@ -6664,21 +6704,13 @@ void intel_enable_gt_powersave(struct drm_i915_private *dev_priv)
66646704
* paths, so the _noresume version is enough (and in case of
66656705
* runtime resume it's necessary).
66666706
*/
6667-
if (schedule_delayed_work(&dev_priv->rps.delayed_resume_work,
6668-
round_jiffies_up_relative(HZ)))
6707+
if (queue_delayed_work(dev_priv->wq,
6708+
&dev_priv->rps.autoenable_work,
6709+
round_jiffies_up_relative(HZ)))
66696710
intel_runtime_pm_get_noresume(dev_priv);
66706711
}
66716712
}
66726713

6673-
void intel_reset_gt_powersave(struct drm_i915_private *dev_priv)
6674-
{
6675-
if (INTEL_INFO(dev_priv)->gen < 6)
6676-
return;
6677-
6678-
gen6_suspend_rps(dev_priv);
6679-
dev_priv->rps.enabled = false;
6680-
}
6681-
66826714
static void ibx_init_clock_gating(struct drm_device *dev)
66836715
{
66846716
struct drm_i915_private *dev_priv = to_i915(dev);
@@ -7785,8 +7817,8 @@ void intel_pm_setup(struct drm_device *dev)
77857817
mutex_init(&dev_priv->rps.hw_lock);
77867818
spin_lock_init(&dev_priv->rps.client_lock);
77877819

7788-
INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
7789-
intel_gen6_powersave_work);
7820+
INIT_DELAYED_WORK(&dev_priv->rps.autoenable_work,
7821+
__intel_autoenable_gt_powersave);
77907822
INIT_LIST_HEAD(&dev_priv->rps.clients);
77917823
INIT_LIST_HEAD(&dev_priv->rps.semaphores.link);
77927824
INIT_LIST_HEAD(&dev_priv->rps.mmioflips.link);

drivers/gpu/drm/i915/intel_uncore.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ void intel_uncore_sanitize(struct drm_i915_private *dev_priv)
435435
i915.enable_rc6 = sanitize_rc6_option(dev_priv, i915.enable_rc6);
436436

437437
/* BIOS often leaves RC6 enabled, but disable it for hw init */
438-
intel_disable_gt_powersave(dev_priv);
438+
intel_sanitize_gt_powersave(dev_priv);
439439
}
440440

441441
static void __intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,

0 commit comments

Comments
 (0)