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