[PATCH 2/2] drm/radeon: add runtime PM support (v2)
Mike Lothian
mike at fireburn.co.uk
Fri Sep 20 13:25:30 PDT 2013
Hi
Is there an easy way to check this is on?
I have radeon.dynpm=1 in grub but usually when I use switcheroo I see
messages saying the card if now off at the moment I can old see messages
saying when the card gets powered up
Is it possible to have the on and off messages appearing?
Cheers
Mike
On 20 September 2013 18:18, Alex Deucher <alexdeucher at gmail.com> wrote:
> From: Dave Airlie <airlied at redhat.com>
>
> This hooks radeon up to the runtime PM system to enable
> dynamic power management for secondary GPUs in switchable
> and powerxpress laptops.
>
> v2: agd5f: clean up, add module parameter
>
> Signed-off-by: Dave Airlie <airlied at redhat.com>
> Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
> ---
> drivers/gpu/drm/radeon/radeon.h | 8 +-
> drivers/gpu/drm/radeon/radeon_atpx_handler.c | 4 +
> drivers/gpu/drm/radeon/radeon_connectors.c | 63 ++++++++++++--
> drivers/gpu/drm/radeon/radeon_device.c | 52 +++++++++---
> drivers/gpu/drm/radeon/radeon_display.c | 47 ++++++++++-
> drivers/gpu/drm/radeon/radeon_drv.c | 122
> +++++++++++++++++++++++++--
> drivers/gpu/drm/radeon/radeon_drv.h | 3 +
> drivers/gpu/drm/radeon/radeon_ioc32.c | 2 +-
> drivers/gpu/drm/radeon/radeon_irq_kms.c | 8 +-
> drivers/gpu/drm/radeon/radeon_kms.c | 26 +++++-
> 10 files changed, 299 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/radeon.h
> b/drivers/gpu/drm/radeon/radeon.h
> index 986100a..ad54525 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -98,6 +98,7 @@ extern int radeon_lockup_timeout;
> extern int radeon_fastfb;
> extern int radeon_dpm;
> extern int radeon_aspm;
> +extern int radeon_runtime_pm;
>
> /*
> * Copy from radeon_drv.h so we don't have to include both and have
> conflicting
> @@ -2212,6 +2213,9 @@ struct radeon_device {
> /* clock, powergating flags */
> u32 cg_flags;
> u32 pg_flags;
> +
> + struct dev_pm_domain vga_pm_domain;
> + bool have_disp_power_ref;
> };
>
> int radeon_device_init(struct radeon_device *rdev,
> @@ -2673,8 +2677,8 @@ extern void radeon_ttm_placement_from_domain(struct
> radeon_bo *rbo, u32 domain);
> extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
> extern void radeon_vram_location(struct radeon_device *rdev, struct
> radeon_mc *mc, u64 base);
> extern void radeon_gtt_location(struct radeon_device *rdev, struct
> radeon_mc *mc);
> -extern int radeon_resume_kms(struct drm_device *dev, bool resume);
> -extern int radeon_suspend_kms(struct drm_device *dev, bool suspend);
> +extern int radeon_resume_kms(struct drm_device *dev, bool resume, bool
> fbcon);
> +extern int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool
> fbcon);
> extern void radeon_ttm_set_active_vram_size(struct radeon_device *rdev,
> u64 size);
> extern void radeon_program_register_sequence(struct radeon_device *rdev,
> const u32 *registers,
> diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c
> b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
> index d96070b..6153ec1 100644
> --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c
> +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
> @@ -59,6 +59,10 @@ struct atpx_mux {
> u16 mux;
> } __packed;
>
> +bool radeon_is_px(void) {
> + return radeon_atpx_priv.atpx_detected;
> +}
> +
> /**
> * radeon_atpx_call - call an ATPX method
> *
> diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c
> b/drivers/gpu/drm/radeon/radeon_connectors.c
> index 79159b5..5855b5b 100644
> --- a/drivers/gpu/drm/radeon/radeon_connectors.c
> +++ b/drivers/gpu/drm/radeon/radeon_connectors.c
> @@ -31,6 +31,8 @@
> #include "radeon.h"
> #include "atom.h"
>
> +#include <linux/pm_runtime.h>
> +
> extern void
> radeon_combios_connected_scratch_regs(struct drm_connector *connector,
> struct drm_encoder *encoder,
> @@ -626,6 +628,11 @@ radeon_lvds_detect(struct drm_connector *connector,
> bool force)
> struct radeon_connector *radeon_connector =
> to_radeon_connector(connector);
> struct drm_encoder *encoder =
> radeon_best_single_encoder(connector);
> enum drm_connector_status ret = connector_status_disconnected;
> + int r;
> +
> + r = pm_runtime_get_sync(connector->dev->dev);
> + if (r < 0)
> + return connector_status_disconnected;
>
> if (encoder) {
> struct radeon_encoder *radeon_encoder =
> to_radeon_encoder(encoder);
> @@ -651,6 +658,8 @@ radeon_lvds_detect(struct drm_connector *connector,
> bool force)
> /* check acpi lid status ??? */
>
> radeon_connector_update_scratch_regs(connector, ret);
> + pm_runtime_mark_last_busy(connector->dev->dev);
> + pm_runtime_put_autosuspend(connector->dev->dev);
> return ret;
> }
>
> @@ -750,6 +759,11 @@ radeon_vga_detect(struct drm_connector *connector,
> bool force)
> struct drm_encoder_helper_funcs *encoder_funcs;
> bool dret = false;
> enum drm_connector_status ret = connector_status_disconnected;
> + int r;
> +
> + r = pm_runtime_get_sync(connector->dev->dev);
> + if (r < 0)
> + return connector_status_disconnected;
>
> encoder = radeon_best_single_encoder(connector);
> if (!encoder)
> @@ -790,9 +804,8 @@ radeon_vga_detect(struct drm_connector *connector,
> bool force)
> * detected a monitor via load.
> */
> if (radeon_connector->detected_by_load)
> - return connector->status;
> - else
> - return ret;
> + ret = connector->status;
> + goto out;
> }
>
> if (radeon_connector->dac_load_detect && encoder) {
> @@ -817,6 +830,11 @@ radeon_vga_detect(struct drm_connector *connector,
> bool force)
> }
>
> radeon_connector_update_scratch_regs(connector, ret);
> +
> +out:
> + pm_runtime_mark_last_busy(connector->dev->dev);
> + pm_runtime_put_autosuspend(connector->dev->dev);
> +
> return ret;
> }
>
> @@ -873,10 +891,15 @@ radeon_tv_detect(struct drm_connector *connector,
> bool force)
> struct drm_encoder_helper_funcs *encoder_funcs;
> struct radeon_connector *radeon_connector =
> to_radeon_connector(connector);
> enum drm_connector_status ret = connector_status_disconnected;
> + int r;
>
> if (!radeon_connector->dac_load_detect)
> return ret;
>
> + r = pm_runtime_get_sync(connector->dev->dev);
> + if (r < 0)
> + return connector_status_disconnected;
> +
> encoder = radeon_best_single_encoder(connector);
> if (!encoder)
> ret = connector_status_disconnected;
> @@ -887,6 +910,8 @@ radeon_tv_detect(struct drm_connector *connector, bool
> force)
> if (ret == connector_status_connected)
> ret =
> radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret,
> false);
> radeon_connector_update_scratch_regs(connector, ret);
> + pm_runtime_mark_last_busy(connector->dev->dev);
> + pm_runtime_put_autosuspend(connector->dev->dev);
> return ret;
> }
>
> @@ -954,12 +979,18 @@ radeon_dvi_detect(struct drm_connector *connector,
> bool force)
> struct drm_encoder *encoder = NULL;
> struct drm_encoder_helper_funcs *encoder_funcs;
> struct drm_mode_object *obj;
> - int i;
> + int i, r;
> enum drm_connector_status ret = connector_status_disconnected;
> bool dret = false, broken_edid = false;
>
> - if (!force && radeon_check_hpd_status_unchanged(connector))
> - return connector->status;
> + r = pm_runtime_get_sync(connector->dev->dev);
> + if (r < 0)
> + return connector_status_disconnected;
> +
> + if (!force && radeon_check_hpd_status_unchanged(connector)) {
> + ret = connector->status;
> + goto exit;
> + }
>
> if (radeon_connector->ddc_bus)
> dret = radeon_ddc_probe(radeon_connector, false);
> @@ -1110,6 +1141,11 @@ out:
>
> /* updated in get modes as well since we need to know if it's
> analog or digital */
> radeon_connector_update_scratch_regs(connector, ret);
> +
> +exit:
> + pm_runtime_mark_last_busy(connector->dev->dev);
> + pm_runtime_put_autosuspend(connector->dev->dev);
> +
> return ret;
> }
>
> @@ -1377,9 +1413,16 @@ radeon_dp_detect(struct drm_connector *connector,
> bool force)
> enum drm_connector_status ret = connector_status_disconnected;
> struct radeon_connector_atom_dig *radeon_dig_connector =
> radeon_connector->con_priv;
> struct drm_encoder *encoder =
> radeon_best_single_encoder(connector);
> + int r;
>
> - if (!force && radeon_check_hpd_status_unchanged(connector))
> - return connector->status;
> + r = pm_runtime_get_sync(connector->dev->dev);
> + if (r < 0)
> + return connector_status_disconnected;
> +
> + if (!force && radeon_check_hpd_status_unchanged(connector)) {
> + ret = connector->status;
> + goto out;
> + }
>
> if (radeon_connector->edid) {
> kfree(radeon_connector->edid);
> @@ -1443,6 +1486,10 @@ radeon_dp_detect(struct drm_connector *connector,
> bool force)
> }
>
> radeon_connector_update_scratch_regs(connector, ret);
> +out:
> + pm_runtime_mark_last_busy(connector->dev->dev);
> + pm_runtime_put_autosuspend(connector->dev->dev);
> +
> return ret;
> }
>
> diff --git a/drivers/gpu/drm/radeon/radeon_device.c
> b/drivers/gpu/drm/radeon/radeon_device.c
> index 37cfcee..b9b9dfd 100644
> --- a/drivers/gpu/drm/radeon/radeon_device.c
> +++ b/drivers/gpu/drm/radeon/radeon_device.c
> @@ -101,6 +101,12 @@ static const char radeon_family_name[][16] = {
> "LAST",
> };
>
> +#if defined(CONFIG_VGA_SWITCHEROO)
> +bool radeon_is_px(void);
> +#else
> +static inline bool radeon_is_px(void) { return false; }
> +#endif
> +
> /**
> * radeon_program_register_sequence - program an array of registers.
> *
> @@ -1076,6 +1082,10 @@ static bool
> radeon_switcheroo_quirk_long_wakeup(struct pci_dev *pdev)
> static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum
> vga_switcheroo_state state)
> {
> struct drm_device *dev = pci_get_drvdata(pdev);
> +
> + if (radeon_is_px() && state == VGA_SWITCHEROO_OFF)
> + return;
> +
> if (state == VGA_SWITCHEROO_ON) {
> unsigned d3_delay = dev->pdev->d3_delay;
>
> @@ -1086,7 +1096,7 @@ static void radeon_switcheroo_set_state(struct
> pci_dev *pdev, enum vga_switchero
> if (d3_delay < 20 &&
> radeon_switcheroo_quirk_long_wakeup(pdev))
> dev->pdev->d3_delay = 20;
>
> - radeon_resume_kms(dev, 1);
> + radeon_resume_kms(dev, true, true);
>
> dev->pdev->d3_delay = d3_delay;
>
> @@ -1096,7 +1106,7 @@ static void radeon_switcheroo_set_state(struct
> pci_dev *pdev, enum vga_switchero
> printk(KERN_INFO "radeon: switched off\n");
> drm_kms_helper_poll_disable(dev);
> dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
> - radeon_suspend_kms(dev, 1);
> + radeon_suspend_kms(dev, true, true);
> dev->switch_power_state = DRM_SWITCH_POWER_OFF;
> }
> }
> @@ -1146,6 +1156,7 @@ int radeon_device_init(struct radeon_device *rdev,
> {
> int r, i;
> int dma_bits;
> + bool runtime = false;
>
> rdev->shutdown = false;
> rdev->dev = &pdev->dev;
> @@ -1292,7 +1303,14 @@ int radeon_device_init(struct radeon_device *rdev,
> /* this will fail for cards that aren't VGA class devices, just
> * ignore it */
> vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode);
> - vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops,
> false);
> +
> + if (radeon_runtime_pm == 1)
> + runtime = true;
> + if ((radeon_runtime_pm == -1) && radeon_is_px())
> + runtime = true;
> + vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops,
> runtime);
> + if (runtime)
> + vga_switcheroo_init_domain_pm_ops(rdev->dev,
> &rdev->vga_pm_domain);
>
> r = radeon_init(rdev);
> if (r)
> @@ -1373,7 +1391,7 @@ void radeon_device_fini(struct radeon_device *rdev)
> * Returns 0 for success or an error on failure.
> * Called at driver suspend.
> */
> -int radeon_suspend_kms(struct drm_device *dev, bool suspend)
> +int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
> {
> struct radeon_device *rdev;
> struct drm_crtc *crtc;
> @@ -1448,9 +1466,12 @@ int radeon_suspend_kms(struct drm_device *dev, bool
> suspend)
> pci_disable_device(dev->pdev);
> pci_set_power_state(dev->pdev, PCI_D3hot);
> }
> - console_lock();
> - radeon_fbdev_set_suspend(rdev, 1);
> - console_unlock();
> +
> + if (fbcon) {
> + console_lock();
> + radeon_fbdev_set_suspend(rdev, 1);
> + console_unlock();
> + }
> return 0;
> }
>
> @@ -1463,7 +1484,7 @@ int radeon_suspend_kms(struct drm_device *dev, bool
> suspend)
> * Returns 0 for success or an error on failure.
> * Called at driver resume.
> */
> -int radeon_resume_kms(struct drm_device *dev, bool resume)
> +int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
> {
> struct drm_connector *connector;
> struct radeon_device *rdev = dev->dev_private;
> @@ -1472,12 +1493,15 @@ int radeon_resume_kms(struct drm_device *dev, bool
> resume)
> if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
> return 0;
>
> - console_lock();
> + if (fbcon) {
> + console_lock();
> + }
> if (resume) {
> pci_set_power_state(dev->pdev, PCI_D0);
> pci_restore_state(dev->pdev);
> if (pci_enable_device(dev->pdev)) {
> - console_unlock();
> + if (fbcon)
> + console_unlock();
> return -1;
> }
> }
> @@ -1492,9 +1516,11 @@ int radeon_resume_kms(struct drm_device *dev, bool
> resume)
> radeon_pm_resume(rdev);
> radeon_restore_bios_scratch_regs(rdev);
>
> - radeon_fbdev_set_suspend(rdev, 0);
> - console_unlock();
> -
> + if (fbcon) {
> + radeon_fbdev_set_suspend(rdev, 0);
> + console_unlock();
> + }
> +
> /* init dig PHYs, disp eng pll */
> if (rdev->is_atom_bios) {
> radeon_atom_encoder_init(rdev);
> diff --git a/drivers/gpu/drm/radeon/radeon_display.c
> b/drivers/gpu/drm/radeon/radeon_display.c
> index 0d1aa05..bc37e33 100644
> --- a/drivers/gpu/drm/radeon/radeon_display.c
> +++ b/drivers/gpu/drm/radeon/radeon_display.c
> @@ -30,6 +30,7 @@
> #include "atom.h"
> #include <asm/div64.h>
>
> +#include <linux/pm_runtime.h>
> #include <drm/drm_crtc_helper.h>
> #include <drm/drm_edid.h>
>
> @@ -494,11 +495,55 @@ unlock_free:
> return r;
> }
>
> +static int
> +radeon_crtc_set_config(struct drm_mode_set *set)
> +{
> + struct drm_device *dev;
> + struct radeon_device *rdev;
> + struct drm_crtc *crtc;
> + bool active = false;
> + int ret;
> +
> + if (!set || !set->crtc)
> + return -EINVAL;
> +
> + dev = set->crtc->dev;
> +
> + ret = pm_runtime_get_sync(dev->dev);
> + if (ret < 0)
> + return ret;
> +
> + ret = drm_crtc_helper_set_config(set);
> +
> + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
> + if (crtc->enabled)
> + active = true;
> +
> + pm_runtime_mark_last_busy(dev->dev);
> +
> + rdev = dev->dev_private;
> + /* if we have active crtcs and we don't have a power ref,
> + take the current one */
> + if (active && !rdev->have_disp_power_ref) {
> + rdev->have_disp_power_ref = true;
> + return ret;
> + }
> + /* if we have no active crtcs, then drop the power ref
> + we got before */
> + if (!active && rdev->have_disp_power_ref) {
> + pm_runtime_put_autosuspend(dev->dev);
> + rdev->have_disp_power_ref = false;
> + }
> +
> + /* drop the power reference we got coming in here */
> + pm_runtime_put_autosuspend(dev->dev);
> + return ret;
> +}
> static const struct drm_crtc_funcs radeon_crtc_funcs = {
> .cursor_set = radeon_crtc_cursor_set,
> .cursor_move = radeon_crtc_cursor_move,
> .gamma_set = radeon_crtc_gamma_set,
> - .set_config = drm_crtc_helper_set_config,
> + .set_config = radeon_crtc_set_config,
> .destroy = radeon_crtc_destroy,
> .page_flip = radeon_crtc_page_flip,
> };
> diff --git a/drivers/gpu/drm/radeon/radeon_drv.c
> b/drivers/gpu/drm/radeon/radeon_drv.c
> index 788bfb0..427c64f 100644
> --- a/drivers/gpu/drm/radeon/radeon_drv.c
> +++ b/drivers/gpu/drm/radeon/radeon_drv.c
> @@ -36,8 +36,9 @@
> #include <drm/drm_pciids.h>
> #include <linux/console.h>
> #include <linux/module.h>
> -
> -
> +#include <linux/pm_runtime.h>
> +#include <linux/vga_switcheroo.h>
> +#include "drm_crtc_helper.h"
> /*
> * KMS wrapper.
> * - 2.0.0 - initial interface
> @@ -87,8 +88,8 @@ void radeon_driver_postclose_kms(struct drm_device *dev,
> struct drm_file *file_priv);
> void radeon_driver_preclose_kms(struct drm_device *dev,
> struct drm_file *file_priv);
> -int radeon_suspend_kms(struct drm_device *dev, bool suspend);
> -int radeon_resume_kms(struct drm_device *dev, bool resume);
> +int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon);
> +int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon);
> u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc);
> int radeon_enable_vblank_kms(struct drm_device *dev, int crtc);
> void radeon_disable_vblank_kms(struct drm_device *dev, int crtc);
> @@ -137,9 +138,11 @@ void radeon_debugfs_cleanup(struct drm_minor *minor);
> #if defined(CONFIG_VGA_SWITCHEROO)
> void radeon_register_atpx_handler(void);
> void radeon_unregister_atpx_handler(void);
> +bool radeon_is_px(void);
> #else
> static inline void radeon_register_atpx_handler(void) {}
> static inline void radeon_unregister_atpx_handler(void) {}
> +static inline bool radeon_is_px(void) { return false; }
> #endif
>
> int radeon_no_wb;
> @@ -162,6 +165,7 @@ int radeon_lockup_timeout = 10000;
> int radeon_fastfb = 0;
> int radeon_dpm = -1;
> int radeon_aspm = -1;
> +int radeon_runtime_pm = -1;
>
> MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
> module_param_named(no_wb, radeon_no_wb, int, 0444);
> @@ -223,6 +227,9 @@ module_param_named(dpm, radeon_dpm, int, 0444);
> MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 =
> auto)");
> module_param_named(aspm, radeon_aspm, int, 0444);
>
> +MODULE_PARM_DESC(runpm, "PX runtime pm (1 = force enable, 0 = disable, -1
> = PX only default)");
> +module_param_named(runpm, radeon_runtime_pm, int, 0444);
> +
> static struct pci_device_id pciidlist[] = {
> radeon_PCI_IDS
> };
> @@ -259,6 +266,7 @@ static int radeon_resume(struct drm_device *dev)
> return 0;
> }
>
> +
> static const struct file_operations radeon_driver_old_fops = {
> .owner = THIS_MODULE,
> .open = drm_open,
> @@ -357,28 +365,121 @@ static int radeon_pmops_suspend(struct device *dev)
> {
> struct pci_dev *pdev = to_pci_dev(dev);
> struct drm_device *drm_dev = pci_get_drvdata(pdev);
> - return radeon_suspend_kms(drm_dev, 1);
> + return radeon_suspend_kms(drm_dev, true, true);
> }
>
> static int radeon_pmops_resume(struct device *dev)
> {
> struct pci_dev *pdev = to_pci_dev(dev);
> struct drm_device *drm_dev = pci_get_drvdata(pdev);
> - return radeon_resume_kms(drm_dev, 1);
> + return radeon_resume_kms(drm_dev, true, true);
> }
>
> static int radeon_pmops_freeze(struct device *dev)
> {
> struct pci_dev *pdev = to_pci_dev(dev);
> struct drm_device *drm_dev = pci_get_drvdata(pdev);
> - return radeon_suspend_kms(drm_dev, 0);
> + return radeon_suspend_kms(drm_dev, false, true);
> }
>
> static int radeon_pmops_thaw(struct device *dev)
> {
> struct pci_dev *pdev = to_pci_dev(dev);
> struct drm_device *drm_dev = pci_get_drvdata(pdev);
> - return radeon_resume_kms(drm_dev, 0);
> + return radeon_resume_kms(drm_dev, false, true);
> +}
> +
> +static int radeon_pmops_runtime_suspend(struct device *dev)
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> + struct drm_device *drm_dev = pci_get_drvdata(pdev);
> + int ret;
> +
> + if (radeon_runtime_pm == 0)
> + return -EINVAL;
> +
> + drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
> + drm_kms_helper_poll_disable(drm_dev);
> + vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
> +
> + ret = radeon_suspend_kms(drm_dev, false, false);
> + pci_save_state(pdev);
> + pci_disable_device(pdev);
> + pci_set_power_state(pdev, PCI_D3cold);
> + drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
> +
> + return 0;
> +}
> +
> +static int radeon_pmops_runtime_resume(struct device *dev)
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> + struct drm_device *drm_dev = pci_get_drvdata(pdev);
> + int ret;
> +
> + if (radeon_runtime_pm == 0)
> + return -EINVAL;
> +
> + drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
> +
> + pci_set_power_state(pdev, PCI_D0);
> + pci_restore_state(pdev);
> + ret = pci_enable_device(pdev);
> + if (ret)
> + return ret;
> + pci_set_master(pdev);
> +
> + ret = radeon_resume_kms(drm_dev, false, false);
> + drm_kms_helper_poll_enable(drm_dev);
> + vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
> + drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
> + return 0;
> +}
> +
> +static int radeon_pmops_runtime_idle(struct device *dev)
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> + struct drm_device *drm_dev = pci_get_drvdata(pdev);
> + struct drm_crtc *crtc;
> +
> + if (radeon_runtime_pm == 0)
> + return -EBUSY;
> +
> + /* are we PX enabled? */
> + if (radeon_runtime_pm == -1 && !radeon_is_px()) {
> + DRM_DEBUG_DRIVER("failing to power off - not px\n");
> + return -EBUSY;
> + }
> +
> + list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
> + if (crtc->enabled) {
> + DRM_DEBUG_DRIVER("failing to power off - crtc
> active\n");
> + return -EBUSY;
> + }
> + }
> +
> + pm_runtime_mark_last_busy(dev);
> + pm_runtime_autosuspend(dev);
> + /* we don't want the main rpm_idle to call suspend - we want to
> autosuspend */
> + return 1;
> +}
> +
> +long radeon_drm_ioctl(struct file *filp,
> + unsigned int cmd, unsigned long arg)
> +{
> + struct drm_file *file_priv = filp->private_data;
> + struct drm_device *dev;
> + long ret;
> + dev = file_priv->minor->dev;
> + ret = pm_runtime_get_sync(dev->dev);
> + if (ret < 0)
> + return ret;
> +
> + ret = drm_ioctl(filp, cmd, arg);
> +
> + pm_runtime_mark_last_busy(dev->dev);
> + pm_runtime_put_autosuspend(dev->dev);
> + return ret;
> }
>
> static const struct dev_pm_ops radeon_pm_ops = {
> @@ -388,13 +489,16 @@ static const struct dev_pm_ops radeon_pm_ops = {
> .thaw = radeon_pmops_thaw,
> .poweroff = radeon_pmops_freeze,
> .restore = radeon_pmops_resume,
> + .runtime_suspend = radeon_pmops_runtime_suspend,
> + .runtime_resume = radeon_pmops_runtime_resume,
> + .runtime_idle = radeon_pmops_runtime_idle,
> };
>
> static const struct file_operations radeon_driver_kms_fops = {
> .owner = THIS_MODULE,
> .open = drm_open,
> .release = drm_release,
> - .unlocked_ioctl = drm_ioctl,
> + .unlocked_ioctl = radeon_drm_ioctl,
> .mmap = radeon_mmap,
> .poll = drm_poll,
> .read = drm_read,
> diff --git a/drivers/gpu/drm/radeon/radeon_drv.h
> b/drivers/gpu/drm/radeon/radeon_drv.h
> index b369d42..543dcfa 100644
> --- a/drivers/gpu/drm/radeon/radeon_drv.h
> +++ b/drivers/gpu/drm/radeon/radeon_drv.h
> @@ -113,6 +113,9 @@
> #define DRIVER_MINOR 33
> #define DRIVER_PATCHLEVEL 0
>
> +long radeon_drm_ioctl(struct file *filp,
> + unsigned int cmd, unsigned long arg);
> +
> /* The rest of the file is DEPRECATED! */
> #ifdef CONFIG_DRM_RADEON_UMS
>
> diff --git a/drivers/gpu/drm/radeon/radeon_ioc32.c
> b/drivers/gpu/drm/radeon/radeon_ioc32.c
> index c180df8..bdb0f93 100644
> --- a/drivers/gpu/drm/radeon/radeon_ioc32.c
> +++ b/drivers/gpu/drm/radeon/radeon_ioc32.c
> @@ -418,7 +418,7 @@ long radeon_kms_compat_ioctl(struct file *filp,
> unsigned int cmd, unsigned long
> if (nr < DRM_COMMAND_BASE)
> return drm_compat_ioctl(filp, cmd, arg);
>
> - ret = drm_ioctl(filp, cmd, arg);
> + ret = radeon_drm_ioctl(filp, cmd, arg);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c
> b/drivers/gpu/drm/radeon/radeon_irq_kms.c
> index cc9e848..ec6240b 100644
> --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
> +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
> @@ -32,6 +32,8 @@
> #include "radeon.h"
> #include "atom.h"
>
> +#include <linux/pm_runtime.h>
> +
> #define RADEON_WAIT_IDLE_TIMEOUT 200
>
> /**
> @@ -47,8 +49,12 @@ irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS)
> {
> struct drm_device *dev = (struct drm_device *) arg;
> struct radeon_device *rdev = dev->dev_private;
> + irqreturn_t ret;
>
> - return radeon_irq_process(rdev);
> + ret = radeon_irq_process(rdev);
> + if (ret == IRQ_HANDLED)
> + pm_runtime_mark_last_busy(dev->dev);
> + return ret;
> }
>
> /*
> diff --git a/drivers/gpu/drm/radeon/radeon_kms.c
> b/drivers/gpu/drm/radeon/radeon_kms.c
> index 61580dd..bffff51 100644
> --- a/drivers/gpu/drm/radeon/radeon_kms.c
> +++ b/drivers/gpu/drm/radeon/radeon_kms.c
> @@ -32,7 +32,7 @@
>
> #include <linux/vga_switcheroo.h>
> #include <linux/slab.h>
> -
> +#include <linux/pm_runtime.h>
> /**
> * radeon_driver_unload_kms - Main unload function for KMS.
> *
> @@ -50,9 +50,14 @@ int radeon_driver_unload_kms(struct drm_device *dev)
>
> if (rdev == NULL)
> return 0;
> +
> if (rdev->rmmio == NULL)
> goto done_free;
> +
> + pm_runtime_get_sync(dev->dev);
> +
> radeon_acpi_fini(rdev);
> +
> radeon_modeset_fini(rdev);
> radeon_device_fini(rdev);
>
> @@ -125,9 +130,20 @@ int radeon_driver_load_kms(struct drm_device *dev,
> unsigned long flags)
> "Error during ACPI methods call\n");
> }
>
> + if (radeon_runtime_pm != 0) {
> + pm_runtime_use_autosuspend(dev->dev);
> + pm_runtime_set_autosuspend_delay(dev->dev, 5000);
> + pm_runtime_set_active(dev->dev);
> + pm_runtime_allow(dev->dev);
> + pm_runtime_mark_last_busy(dev->dev);
> + pm_runtime_put_autosuspend(dev->dev);
> + }
> +
> out:
> if (r)
> radeon_driver_unload_kms(dev);
> +
> +
> return r;
> }
>
> @@ -475,9 +491,14 @@ void radeon_driver_lastclose_kms(struct drm_device
> *dev)
> int radeon_driver_open_kms(struct drm_device *dev, struct drm_file
> *file_priv)
> {
> struct radeon_device *rdev = dev->dev_private;
> + int r;
>
> file_priv->driver_priv = NULL;
>
> + r = pm_runtime_get_sync(dev->dev);
> + if (r < 0)
> + return r;
> +
> /* new gpu have virtual address space support */
> if (rdev->family >= CHIP_CAYMAN) {
> struct radeon_fpriv *fpriv;
> @@ -506,6 +527,9 @@ int radeon_driver_open_kms(struct drm_device *dev,
> struct drm_file *file_priv)
>
> file_priv->driver_priv = fpriv;
> }
> +
> + pm_runtime_mark_last_busy(dev->dev);
> + pm_runtime_put_autosuspend(dev->dev);
> return 0;
> }
>
> --
> 1.8.3.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/dri-devel/attachments/20130920/cb790232/attachment-0001.html>
More information about the dri-devel
mailing list