drm/gma500: Rewrite power management code
Rewrite the power.c code. For some reason this was doing locking + refcounting + state (suspended or not) bookkeeping all by itself. But there is no reason for this, this is all taken care of by the runtime-pm core, through pm_runtime_get()/_put(). Besides this not being necessary the DIY code is also quite weird/ buggy in some places. E.g. power_begin() would manually do a resume when not resumed already and force_on=true, followed by a pm_runtime_get(), which will cause a call to gma_power_resume() to get scheduled which would redo the entire resume again. Which can all be replaced by a single pm_runtime_get_sync() call. Note that this is just a cleanup, this does not actually fix the (disabled through #if 0) runtime-pm support. It does now call pm_runtime_enable(), but only after doing a pm_runtime_get() at probe-time, so the device is never runtime suspended. Doing this permanent get() + enable() instead of not calling enable() at all is necessary for the pm_runtime_get_if_in_use() call in gma_power_begin() to work properly. Note this also removes the gma_power_is_on() call a check like this without actually holding a reference is always racy, so it is a bad idea (and therefor has no pm_runtime_foo() equivalent). The 2 code paths which were using gma_power_is_on() are actually both guaranteed to only run when the device is powered-on so the 2 checks can simply be dropped. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Patrik Jakobsson <patrik.r.jakobsson@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20220909115646.99920-6-hdegoede@redhat.com
This commit is contained in:
parent
d35a4bf660
commit
672c473576
|
@ -61,7 +61,6 @@ static void oaktrail_lvds_set_power(struct drm_device *dev,
|
||||||
pp_status = REG_READ(PP_STATUS);
|
pp_status = REG_READ(PP_STATUS);
|
||||||
} while (pp_status & PP_ON);
|
} while (pp_status & PP_ON);
|
||||||
dev_priv->is_lvds_on = false;
|
dev_priv->is_lvds_on = false;
|
||||||
pm_request_idle(dev->dev);
|
|
||||||
}
|
}
|
||||||
gma_power_end(dev);
|
gma_power_end(dev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,6 @@
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
static struct mutex power_mutex; /* Serialize power ops */
|
|
||||||
static DEFINE_SPINLOCK(power_ctrl_lock); /* Serialize power claim */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gma_power_init - initialise power manager
|
* gma_power_init - initialise power manager
|
||||||
* @dev: our device
|
* @dev: our device
|
||||||
|
@ -54,13 +51,23 @@ void gma_power_init(struct drm_device *dev)
|
||||||
dev_priv->apm_base = dev_priv->apm_reg & 0xffff;
|
dev_priv->apm_base = dev_priv->apm_reg & 0xffff;
|
||||||
dev_priv->ospm_base &= 0xffff;
|
dev_priv->ospm_base &= 0xffff;
|
||||||
|
|
||||||
dev_priv->display_power = true; /* We start active */
|
|
||||||
dev_priv->display_count = 0; /* Currently no users */
|
|
||||||
dev_priv->suspended = false; /* And not suspended */
|
|
||||||
mutex_init(&power_mutex);
|
|
||||||
|
|
||||||
if (dev_priv->ops->init_pm)
|
if (dev_priv->ops->init_pm)
|
||||||
dev_priv->ops->init_pm(dev);
|
dev_priv->ops->init_pm(dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Runtime pm support is broken atm. So for now unconditionally
|
||||||
|
* call pm_runtime_get() here and put it again in psb_driver_unload()
|
||||||
|
*
|
||||||
|
* To fix this we need to call pm_runtime_get() once for each active
|
||||||
|
* pipe at boot and then put() / get() for each pipe disable / enable
|
||||||
|
* so that the device gets runtime suspended when no pipes are active.
|
||||||
|
* Once this is in place the pm_runtime_get() below should be replaced
|
||||||
|
* by a pm_runtime_allow() call to undo the pm_runtime_forbid() from
|
||||||
|
* pci_pm_init().
|
||||||
|
*/
|
||||||
|
pm_runtime_get(dev->dev);
|
||||||
|
|
||||||
|
dev_priv->pm_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,8 +78,12 @@ void gma_power_init(struct drm_device *dev)
|
||||||
*/
|
*/
|
||||||
void gma_power_uninit(struct drm_device *dev)
|
void gma_power_uninit(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
pm_runtime_disable(dev->dev);
|
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
|
||||||
pm_runtime_set_suspended(dev->dev);
|
|
||||||
|
if (!dev_priv->pm_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pm_runtime_put_noidle(dev->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,11 +96,8 @@ static void gma_suspend_display(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
|
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
|
||||||
|
|
||||||
if (dev_priv->suspended)
|
|
||||||
return;
|
|
||||||
dev_priv->ops->save_regs(dev);
|
dev_priv->ops->save_regs(dev);
|
||||||
dev_priv->ops->power_down(dev);
|
dev_priv->ops->power_down(dev);
|
||||||
dev_priv->display_power = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,8 +114,6 @@ static void gma_resume_display(struct pci_dev *pdev)
|
||||||
|
|
||||||
/* turn on the display power island */
|
/* turn on the display power island */
|
||||||
dev_priv->ops->power_up(dev);
|
dev_priv->ops->power_up(dev);
|
||||||
dev_priv->suspended = false;
|
|
||||||
dev_priv->display_power = true;
|
|
||||||
|
|
||||||
PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL);
|
PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL);
|
||||||
pci_write_config_word(pdev, PSB_GMCH_CTRL,
|
pci_write_config_word(pdev, PSB_GMCH_CTRL,
|
||||||
|
@ -131,9 +137,6 @@ static void gma_suspend_pci(struct pci_dev *pdev)
|
||||||
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
|
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
|
||||||
int bsm, vbt;
|
int bsm, vbt;
|
||||||
|
|
||||||
if (dev_priv->suspended)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pci_save_state(pdev);
|
pci_save_state(pdev);
|
||||||
pci_read_config_dword(pdev, 0x5C, &bsm);
|
pci_read_config_dword(pdev, 0x5C, &bsm);
|
||||||
dev_priv->regs.saveBSM = bsm;
|
dev_priv->regs.saveBSM = bsm;
|
||||||
|
@ -142,8 +145,6 @@ static void gma_suspend_pci(struct pci_dev *pdev)
|
||||||
|
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
pci_set_power_state(pdev, PCI_D3hot);
|
pci_set_power_state(pdev, PCI_D3hot);
|
||||||
|
|
||||||
dev_priv->suspended = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -153,26 +154,17 @@ static void gma_suspend_pci(struct pci_dev *pdev)
|
||||||
* Perform the resume processing on our PCI device state - rewrite
|
* Perform the resume processing on our PCI device state - rewrite
|
||||||
* register state and re-enable the PCI device
|
* register state and re-enable the PCI device
|
||||||
*/
|
*/
|
||||||
static bool gma_resume_pci(struct pci_dev *pdev)
|
static int gma_resume_pci(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||||
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
|
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!dev_priv->suspended)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
pci_set_power_state(pdev, PCI_D0);
|
pci_set_power_state(pdev, PCI_D0);
|
||||||
pci_restore_state(pdev);
|
pci_restore_state(pdev);
|
||||||
pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM);
|
pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM);
|
||||||
pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT);
|
pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT);
|
||||||
ret = pci_enable_device(pdev);
|
|
||||||
|
|
||||||
if (ret != 0)
|
return pci_enable_device(pdev);
|
||||||
dev_err(&pdev->dev, "pci_enable failed: %d\n", ret);
|
|
||||||
else
|
|
||||||
dev_priv->suspended = false;
|
|
||||||
return !dev_priv->suspended;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,20 +179,10 @@ int gma_power_suspend(struct device *_dev)
|
||||||
{
|
{
|
||||||
struct pci_dev *pdev = to_pci_dev(_dev);
|
struct pci_dev *pdev = to_pci_dev(_dev);
|
||||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||||
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
|
|
||||||
|
|
||||||
mutex_lock(&power_mutex);
|
gma_irq_uninstall(dev);
|
||||||
if (!dev_priv->suspended) {
|
gma_suspend_display(dev);
|
||||||
if (dev_priv->display_count) {
|
gma_suspend_pci(pdev);
|
||||||
mutex_unlock(&power_mutex);
|
|
||||||
dev_err(dev->dev, "GPU hardware busy, cannot suspend\n");
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
gma_irq_uninstall(dev);
|
|
||||||
gma_suspend_display(dev);
|
|
||||||
gma_suspend_pci(pdev);
|
|
||||||
}
|
|
||||||
mutex_unlock(&power_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,26 +197,12 @@ int gma_power_resume(struct device *_dev)
|
||||||
struct pci_dev *pdev = to_pci_dev(_dev);
|
struct pci_dev *pdev = to_pci_dev(_dev);
|
||||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||||
|
|
||||||
mutex_lock(&power_mutex);
|
|
||||||
gma_resume_pci(pdev);
|
gma_resume_pci(pdev);
|
||||||
gma_resume_display(pdev);
|
gma_resume_display(pdev);
|
||||||
gma_irq_install(dev);
|
gma_irq_install(dev);
|
||||||
mutex_unlock(&power_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gma_power_is_on - returne true if power is on
|
|
||||||
* @dev: our DRM device
|
|
||||||
*
|
|
||||||
* Returns true if the display island power is on at this moment
|
|
||||||
*/
|
|
||||||
bool gma_power_is_on(struct drm_device *dev)
|
|
||||||
{
|
|
||||||
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
|
|
||||||
return dev_priv->display_power;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gma_power_begin - begin requiring power
|
* gma_power_begin - begin requiring power
|
||||||
* @dev: our DRM device
|
* @dev: our DRM device
|
||||||
|
@ -245,35 +213,10 @@ bool gma_power_is_on(struct drm_device *dev)
|
||||||
*/
|
*/
|
||||||
bool gma_power_begin(struct drm_device *dev, bool force_on)
|
bool gma_power_begin(struct drm_device *dev, bool force_on)
|
||||||
{
|
{
|
||||||
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
|
if (force_on)
|
||||||
struct pci_dev *pdev = to_pci_dev(dev->dev);
|
return pm_runtime_resume_and_get(dev->dev) == 0;
|
||||||
int ret;
|
else
|
||||||
unsigned long flags;
|
return pm_runtime_get_if_in_use(dev->dev) == 1;
|
||||||
|
|
||||||
spin_lock_irqsave(&power_ctrl_lock, flags);
|
|
||||||
/* Power already on ? */
|
|
||||||
if (dev_priv->display_power) {
|
|
||||||
dev_priv->display_count++;
|
|
||||||
pm_runtime_get(dev->dev);
|
|
||||||
spin_unlock_irqrestore(&power_ctrl_lock, flags);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (force_on == false)
|
|
||||||
goto out_false;
|
|
||||||
|
|
||||||
/* Ok power up needed */
|
|
||||||
ret = gma_resume_pci(pdev);
|
|
||||||
if (ret == 0) {
|
|
||||||
gma_irq_preinstall(dev);
|
|
||||||
gma_irq_postinstall(dev);
|
|
||||||
pm_runtime_get(dev->dev);
|
|
||||||
dev_priv->display_count++;
|
|
||||||
spin_unlock_irqrestore(&power_ctrl_lock, flags);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
out_false:
|
|
||||||
spin_unlock_irqrestore(&power_ctrl_lock, flags);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -285,12 +228,6 @@ out_false:
|
||||||
*/
|
*/
|
||||||
void gma_power_end(struct drm_device *dev)
|
void gma_power_end(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
|
|
||||||
unsigned long flags;
|
|
||||||
spin_lock_irqsave(&power_ctrl_lock, flags);
|
|
||||||
dev_priv->display_count--;
|
|
||||||
WARN_ON(dev_priv->display_count < 0);
|
|
||||||
spin_unlock_irqrestore(&power_ctrl_lock, flags);
|
|
||||||
pm_runtime_put(dev->dev);
|
pm_runtime_put(dev->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,16 +241,6 @@ int psb_runtime_resume(struct device *dev)
|
||||||
return gma_power_resume(dev);
|
return gma_power_resume(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
int psb_runtime_idle(struct device *dev)
|
|
||||||
{
|
|
||||||
struct drm_device *drmdev = pci_get_drvdata(to_pci_dev(dev));
|
|
||||||
struct drm_psb_private *dev_priv = to_drm_psb_private(drmdev);
|
|
||||||
if (dev_priv->display_count)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gma_power_thaw(struct device *_dev)
|
int gma_power_thaw(struct device *_dev)
|
||||||
{
|
{
|
||||||
return gma_power_resume(_dev);
|
return gma_power_resume(_dev);
|
||||||
|
|
|
@ -54,19 +54,10 @@ int gma_power_restore(struct device *_dev);
|
||||||
bool gma_power_begin(struct drm_device *dev, bool force);
|
bool gma_power_begin(struct drm_device *dev, bool force);
|
||||||
void gma_power_end(struct drm_device *dev);
|
void gma_power_end(struct drm_device *dev);
|
||||||
|
|
||||||
/*
|
|
||||||
* Use this function to do an instantaneous check for if the hw is on.
|
|
||||||
* Only use this in cases where you know the mutex is already held such
|
|
||||||
* as in irq install/uninstall and you need to
|
|
||||||
* prevent a deadlock situation. Otherwise use gma_power_begin().
|
|
||||||
*/
|
|
||||||
bool gma_power_is_on(struct drm_device *dev);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GFX-Runtime PM callbacks
|
* GFX-Runtime PM callbacks
|
||||||
*/
|
*/
|
||||||
int psb_runtime_suspend(struct device *dev);
|
int psb_runtime_suspend(struct device *dev);
|
||||||
int psb_runtime_resume(struct device *dev);
|
int psb_runtime_resume(struct device *dev);
|
||||||
int psb_runtime_idle(struct device *dev);
|
|
||||||
|
|
||||||
#endif /*_PSB_POWERMGMT_H_*/
|
#endif /*_PSB_POWERMGMT_H_*/
|
||||||
|
|
|
@ -407,11 +407,6 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
psb_intel_opregion_enable_asle(dev);
|
psb_intel_opregion_enable_asle(dev);
|
||||||
#if 0
|
|
||||||
/* Enable runtime pm at last */
|
|
||||||
pm_runtime_enable(dev->dev);
|
|
||||||
pm_runtime_set_active(dev->dev);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return devm_add_action_or_reset(dev->dev, psb_device_release, dev);
|
return devm_add_action_or_reset(dev->dev, psb_device_release, dev);
|
||||||
|
|
||||||
|
@ -484,7 +479,6 @@ static const struct dev_pm_ops psb_pm_ops = {
|
||||||
.restore = gma_power_restore,
|
.restore = gma_power_restore,
|
||||||
.runtime_suspend = psb_runtime_suspend,
|
.runtime_suspend = psb_runtime_suspend,
|
||||||
.runtime_resume = psb_runtime_resume,
|
.runtime_resume = psb_runtime_resume,
|
||||||
.runtime_idle = psb_runtime_idle,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations psb_gem_fops = {
|
static const struct file_operations psb_gem_fops = {
|
||||||
|
|
|
@ -426,9 +426,7 @@ struct drm_psb_private {
|
||||||
spinlock_t irqmask_lock;
|
spinlock_t irqmask_lock;
|
||||||
|
|
||||||
/* Power */
|
/* Power */
|
||||||
bool suspended;
|
bool pm_initialized;
|
||||||
bool display_power;
|
|
||||||
int display_count;
|
|
||||||
|
|
||||||
/* Modesetting */
|
/* Modesetting */
|
||||||
struct psb_intel_mode_device mode_dev;
|
struct psb_intel_mode_device mode_dev;
|
||||||
|
|
|
@ -228,7 +228,7 @@ static irqreturn_t gma_irq_handler(int irq, void *arg)
|
||||||
vdc_stat &= dev_priv->vdc_irq_mask;
|
vdc_stat &= dev_priv->vdc_irq_mask;
|
||||||
spin_unlock(&dev_priv->irqmask_lock);
|
spin_unlock(&dev_priv->irqmask_lock);
|
||||||
|
|
||||||
if (dsp_int && gma_power_is_on(dev)) {
|
if (dsp_int) {
|
||||||
gma_vdc_interrupt(dev, vdc_stat);
|
gma_vdc_interrupt(dev, vdc_stat);
|
||||||
handled = 1;
|
handled = 1;
|
||||||
}
|
}
|
||||||
|
@ -264,13 +264,12 @@ void gma_irq_preinstall(struct drm_device *dev)
|
||||||
|
|
||||||
spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
|
spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
|
||||||
|
|
||||||
if (gma_power_is_on(dev)) {
|
PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
|
||||||
PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
|
PSB_WVDC32(0x00000000, PSB_INT_MASK_R);
|
||||||
PSB_WVDC32(0x00000000, PSB_INT_MASK_R);
|
PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R);
|
||||||
PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R);
|
PSB_WSGX32(0x00000000, PSB_CR_EVENT_HOST_ENABLE);
|
||||||
PSB_WSGX32(0x00000000, PSB_CR_EVENT_HOST_ENABLE);
|
PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE);
|
||||||
PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE);
|
|
||||||
}
|
|
||||||
if (dev->vblank[0].enabled)
|
if (dev->vblank[0].enabled)
|
||||||
dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG;
|
dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG;
|
||||||
if (dev->vblank[1].enabled)
|
if (dev->vblank[1].enabled)
|
||||||
|
|
Loading…
Reference in New Issue