On Fri, Sep 20, 2013 at 4:25 PM, Mike Lothian <mike@xxxxxxxxxxxxxx> 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@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