mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 14:19:16 +00:00
drm/i915: Disable C3 when enabling vblank interrupts on i945gm
The AGPBUSY thing doesn't work on i945gm anymore. This means the gmch is incapable of waking the CPU from C3 when an interrupt is generated. The interrupts just get postponed indefinitely until something wakes up the CPU. This is rather annoying for vblank interrupts as we are unable to maintain a steady framerate unless the machine is sufficiently loaded to stay out of C3. To combat this let's use pm_qos to prevent C3 whenever vblank interrupts are enabled. To maintain reasonable amount of powersaving we will attempt to limit this to C3 only while leaving C1 and C2 enabled. v2: Use READ_ONCE() (Chris) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=30364 Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190322180804.3300-1-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
57b1c4460d
commit
d938da6b13
2 changed files with 96 additions and 0 deletions
|
@ -2042,6 +2042,14 @@ struct drm_i915_private {
|
||||||
struct i915_vma *scratch;
|
struct i915_vma *scratch;
|
||||||
} gt;
|
} gt;
|
||||||
|
|
||||||
|
/* For i945gm vblank irq vs. C3 workaround */
|
||||||
|
struct {
|
||||||
|
struct work_struct work;
|
||||||
|
struct pm_qos_request pm_qos;
|
||||||
|
u8 c3_disable_latency;
|
||||||
|
u8 enabled;
|
||||||
|
} i945gm_vblank;
|
||||||
|
|
||||||
/* perform PHY state sanity checks? */
|
/* perform PHY state sanity checks? */
|
||||||
bool chv_phy_assert[2];
|
bool chv_phy_assert[2];
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <linux/sysrq.h>
|
#include <linux/sysrq.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/cpuidle.h>
|
||||||
#include <linux/circ_buf.h>
|
#include <linux/circ_buf.h>
|
||||||
#include <drm/drm_irq.h>
|
#include <drm/drm_irq.h>
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
|
@ -3131,6 +3132,16 @@ static int i8xx_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int i945gm_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
|
||||||
|
if (dev_priv->i945gm_vblank.enabled++ == 0)
|
||||||
|
schedule_work(&dev_priv->i945gm_vblank.work);
|
||||||
|
|
||||||
|
return i8xx_enable_vblank(dev, pipe);
|
||||||
|
}
|
||||||
|
|
||||||
static int i965_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
static int i965_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
@ -3195,6 +3206,16 @@ static void i8xx_disable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||||
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void i945gm_disable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
|
||||||
|
i8xx_disable_vblank(dev, pipe);
|
||||||
|
|
||||||
|
if (--dev_priv->i945gm_vblank.enabled == 0)
|
||||||
|
schedule_work(&dev_priv->i945gm_vblank.work);
|
||||||
|
}
|
||||||
|
|
||||||
static void i965_disable_vblank(struct drm_device *dev, unsigned int pipe)
|
static void i965_disable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
@ -3228,6 +3249,60 @@ static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||||
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void i945gm_vblank_work_func(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv =
|
||||||
|
container_of(work, struct drm_i915_private, i945gm_vblank.work);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vblank interrupts fail to wake up the device from C3,
|
||||||
|
* hence we want to prevent C3 usage while vblank interrupts
|
||||||
|
* are enabled.
|
||||||
|
*/
|
||||||
|
pm_qos_update_request(&dev_priv->i945gm_vblank.pm_qos,
|
||||||
|
READ_ONCE(dev_priv->i945gm_vblank.enabled) ?
|
||||||
|
dev_priv->i945gm_vblank.c3_disable_latency :
|
||||||
|
PM_QOS_DEFAULT_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cstate_disable_latency(const char *name)
|
||||||
|
{
|
||||||
|
const struct cpuidle_driver *drv;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
drv = cpuidle_get_driver();
|
||||||
|
if (!drv)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < drv->state_count; i++) {
|
||||||
|
const struct cpuidle_state *state = &drv->states[i];
|
||||||
|
|
||||||
|
if (!strcmp(state->name, name))
|
||||||
|
return state->exit_latency ?
|
||||||
|
state->exit_latency - 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i945gm_vblank_work_init(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
INIT_WORK(&dev_priv->i945gm_vblank.work,
|
||||||
|
i945gm_vblank_work_func);
|
||||||
|
|
||||||
|
dev_priv->i945gm_vblank.c3_disable_latency =
|
||||||
|
cstate_disable_latency("C3");
|
||||||
|
pm_qos_add_request(&dev_priv->i945gm_vblank.pm_qos,
|
||||||
|
PM_QOS_CPU_DMA_LATENCY,
|
||||||
|
PM_QOS_DEFAULT_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i945gm_vblank_work_fini(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
cancel_work_sync(&dev_priv->i945gm_vblank.work);
|
||||||
|
pm_qos_remove_request(&dev_priv->i945gm_vblank.pm_qos);
|
||||||
|
}
|
||||||
|
|
||||||
static void ibx_irq_reset(struct drm_i915_private *dev_priv)
|
static void ibx_irq_reset(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
if (HAS_PCH_NOP(dev_priv))
|
if (HAS_PCH_NOP(dev_priv))
|
||||||
|
@ -4525,6 +4600,9 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
|
||||||
struct intel_rps *rps = &dev_priv->gt_pm.rps;
|
struct intel_rps *rps = &dev_priv->gt_pm.rps;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (IS_I945GM(dev_priv))
|
||||||
|
i945gm_vblank_work_init(dev_priv);
|
||||||
|
|
||||||
intel_hpd_init_work(dev_priv);
|
intel_hpd_init_work(dev_priv);
|
||||||
|
|
||||||
INIT_WORK(&rps->work, gen6_pm_rps_work);
|
INIT_WORK(&rps->work, gen6_pm_rps_work);
|
||||||
|
@ -4647,6 +4725,13 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
|
||||||
dev->driver->irq_uninstall = i8xx_irq_reset;
|
dev->driver->irq_uninstall = i8xx_irq_reset;
|
||||||
dev->driver->enable_vblank = i8xx_enable_vblank;
|
dev->driver->enable_vblank = i8xx_enable_vblank;
|
||||||
dev->driver->disable_vblank = i8xx_disable_vblank;
|
dev->driver->disable_vblank = i8xx_disable_vblank;
|
||||||
|
} else if (IS_I945GM(dev_priv)) {
|
||||||
|
dev->driver->irq_preinstall = i915_irq_reset;
|
||||||
|
dev->driver->irq_postinstall = i915_irq_postinstall;
|
||||||
|
dev->driver->irq_uninstall = i915_irq_reset;
|
||||||
|
dev->driver->irq_handler = i915_irq_handler;
|
||||||
|
dev->driver->enable_vblank = i945gm_enable_vblank;
|
||||||
|
dev->driver->disable_vblank = i945gm_disable_vblank;
|
||||||
} else if (IS_GEN(dev_priv, 3)) {
|
} else if (IS_GEN(dev_priv, 3)) {
|
||||||
dev->driver->irq_preinstall = i915_irq_reset;
|
dev->driver->irq_preinstall = i915_irq_reset;
|
||||||
dev->driver->irq_postinstall = i915_irq_postinstall;
|
dev->driver->irq_postinstall = i915_irq_postinstall;
|
||||||
|
@ -4677,6 +4762,9 @@ void intel_irq_fini(struct drm_i915_private *i915)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (IS_I945GM(i915))
|
||||||
|
i945gm_vblank_work_fini(i915);
|
||||||
|
|
||||||
for (i = 0; i < MAX_L3_SLICES; ++i)
|
for (i = 0; i < MAX_L3_SLICES; ++i)
|
||||||
kfree(i915->l3_parity.remap_info[i]);
|
kfree(i915->l3_parity.remap_info[i]);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue