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

Alex Deucher alexdeucher at gmail.com
Fri Sep 20 14:05:19 PDT 2013


On Fri, Sep 20, 2013 at 4:25 PM, Mike Lothian <mike at fireburn.co.uk> wrote:
> Hi
>
> Is there an easy way to check this is on?

It's on by default if your system is a powerxpress system (hybrid laptop).

>
> 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
>

The option is radeon.runpm for this.  Note that only powerxpress
systems are supported.  There is no support for powering down
arbitrary cards yet.

> Is it possible to have the on and off messages appearing?

On a supported system, you will see suspend and resume messages when
when the card is powered down/up.

Alex

>
> 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
>
>


More information about the dri-devel mailing list