It's probably easier if I just show you this:
Is that expected behaviour? I'm used to seeing something more definite when echoing OFF into /sys/kernel/debug/vgaswitcheroo/switch
I've just confirmed with powertop that the laptop is using 26 watts when idle and 47 watts with DRI_PRIME=1 glxgears running
On 20 September 2013 22:12, Alex Deucher alexdeucher@gmail.com wrote:
On Fri, Sep 20, 2013 at 6:10 PM, Mike Lothian mike@fireburn.co.uk wrote:
Sorry that was a typo on my part. I'm using radeon.runpm=1
I can see audio is switched off
[drm] Disabling audio 0 support
When I use DRI_PRIME=1 I see the DRM initialisation for my card each
time I
fire up an application or run glxinfo
Yup. that's the card resuming.
There isn't any explicit messages that the card is on of off however
How can I tell if I have a powerxpress card?
If you have a laptop with an integrated GPU and a discrete GPU. You should see a message about atpx.
Alex
Thanks again
Mike
On 20 Sep 2013 22:05, "Alex Deucher" alexdeucher@gmail.com wrote:
On Fri, Sep 20, 2013 at 4:25 PM, Mike Lothian mike@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@gmail.com
wrote:
From: Dave Airlie airlied@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@redhat.com Signed-off-by: Alex Deucher alexander.deucher@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@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel