drm/radeon: add runtime PM support (v2)
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>
This commit is contained in:
Родитель
7473e830c4
Коммит
10ebc0bc09
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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,
|
||||
|
@ -641,6 +643,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);
|
||||
|
@ -666,6 +673,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;
|
||||
}
|
||||
|
||||
|
@ -765,6 +774,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)
|
||||
|
@ -805,9 +819,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) {
|
||||
|
@ -832,6 +845,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;
|
||||
}
|
||||
|
||||
|
@ -888,10 +906,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;
|
||||
|
@ -902,6 +925,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;
|
||||
}
|
||||
|
||||
|
@ -969,12 +994,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);
|
||||
|
@ -1125,6 +1156,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;
|
||||
}
|
||||
|
||||
|
@ -1392,9 +1428,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);
|
||||
|
@ -1458,6 +1501,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
@ -1382,7 +1400,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;
|
||||
|
@ -1457,9 +1475,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;
|
||||
}
|
||||
|
||||
|
@ -1472,7 +1493,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;
|
||||
|
@ -1481,12 +1502,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;
|
||||
}
|
||||
}
|
||||
|
@ -1501,9 +1525,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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
@ -136,9 +137,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;
|
||||
|
@ -161,6 +164,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);
|
||||
|
@ -222,6 +226,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
|
||||
};
|
||||
|
@ -258,6 +265,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,
|
||||
|
@ -356,28 +364,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 = {
|
||||
|
@ -387,13 +488,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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче