Re: [PATCH 2/2] drm/radeon: add runtime PM support (v2)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxx> wrote:
From: Dave Airlie <airlied@xxxxxxxxxx>

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@xxxxxxxxxx>
Signed-off-by: Alex Deucher <alexander.deucher@xxxxxxx>
---
 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@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/dri-devel

[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux