From: Dave Airlie airlied@redhat.com
This is required to decide if we can auto-powerdown and how to implement it.
Signed-off-by: Dave Airlie airlied@redhat.com --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 30 ++++++++++++++++++------------ drivers/gpu/drm/nouveau/nouveau_acpi.h | 4 ++++ 2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 48783e1..d97f200 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -35,6 +35,14 @@ static struct nouveau_dsm_priv { acpi_handle rom_handle; } nouveau_dsm_priv;
+bool nouveau_is_optimus(void) { + return nouveau_dsm_priv.optimus_detected; +} + +bool nouveau_is_v1_dsm(void) { + return nouveau_dsm_priv.dsm_detected; +} + #define NOUVEAU_DSM_HAS_MUX 0x1 #define NOUVEAU_DSM_HAS_OPT 0x2
@@ -183,9 +191,7 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero
static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id) { - /* perhaps the _DSM functions are mutually exclusive, but prepare for - * the future */ - if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected) + if (!nouveau_dsm_priv.dsm_detected) return 0; if (id == VGA_SWITCHEROO_IGD) return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA); @@ -201,7 +207,7 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
/* Optimus laptops have the card already disabled in * nouveau_switcheroo_set_state */ - if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected) + if (!nouveau_dsm_priv.dsm_detected) return 0;
return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state); @@ -283,24 +289,24 @@ static bool nouveau_dsm_detect(void) has_optimus = 1; }
- if (vga_count == 2 && has_dsm && guid_valid) { + /* find the optimus DSM or the old v1 DSM */ + if (has_optimus == 1) { acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); - printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", + printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n", acpi_method_name); - nouveau_dsm_priv.dsm_detected = true; + nouveau_dsm_priv.optimus_detected = true; ret = true; - } - - if (has_optimus == 1) { + } else if (vga_count == 2 && has_dsm && guid_valid) { acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); - printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n", + printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", acpi_method_name); - nouveau_dsm_priv.optimus_detected = true; + nouveau_dsm_priv.dsm_detected = true; ret = true; }
+ return ret; }
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.h b/drivers/gpu/drm/nouveau/nouveau_acpi.h index 08af677..d0da230 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.h +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.h @@ -4,6 +4,8 @@ #define ROM_BIOS_PAGE 4096
#if defined(CONFIG_ACPI) +bool nouveau_is_optimus(void); +bool nouveau_is_v1_dsm(void); void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); void nouveau_switcheroo_optimus_dsm(void); @@ -11,6 +13,8 @@ int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); bool nouveau_acpi_rom_supported(struct pci_dev *pdev); void *nouveau_acpi_edid(struct drm_device *, struct drm_connector *); #else +static inline bool nouveau_is_optimus(void) { return false; }; +static inline bool nouveau_is_v1_dsm(void) { return false; }; static inline void nouveau_register_dsm_handler(void) {} static inline void nouveau_unregister_dsm_handler(void) {} static inline void nouveau_switcheroo_optimus_dsm(void) {}
From: Dave Airlie airlied@redhat.com
This is a precursor to dynamic power management support for nouveau,
we need to use pm ops for that, so first convert the driver to using pm ops interfaces.
Signed-off-by: Dave Airlie airlied@redhat.com --- drivers/gpu/drm/nouveau/nouveau_drm.c | 93 +++++++++++++++++++++++++---------- drivers/gpu/drm/nouveau/nouveau_drm.h | 4 +- drivers/gpu/drm/nouveau/nouveau_vga.c | 5 +- 3 files changed, 71 insertions(+), 31 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index ccae8c2..85aa1a6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -392,17 +392,12 @@ nouveau_drm_remove(struct pci_dev *pdev) }
int -nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) +nouveau_do_suspend(struct drm_device *dev) { - struct drm_device *dev = pci_get_drvdata(pdev); struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; int ret;
- if (dev->switch_power_state == DRM_SWITCH_POWER_OFF || - pm_state.event == PM_EVENT_PRETHAW) - return 0; - NV_INFO(drm, "suspending fbcon...\n"); nouveau_fbcon_set_suspend(dev, 1);
@@ -431,13 +426,6 @@ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) goto fail_client;
nouveau_agp_fini(drm); - - pci_save_state(pdev); - if (pm_state.event == PM_EVENT_SUSPEND) { - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - } - return 0;
fail_client: @@ -450,24 +438,33 @@ fail_client: return ret; }
-int -nouveau_drm_resume(struct pci_dev *pdev) +int nouveau_pmops_suspend(struct device *dev) { - struct drm_device *dev = pci_get_drvdata(pdev); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_cli *cli; + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); int ret;
- if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) + if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0;
- NV_INFO(drm, "re-enabling device...\n"); - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - ret = pci_enable_device(pdev); + ret = nouveau_do_suspend(drm_dev); if (ret) return ret; - pci_set_master(pdev); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +int +nouveau_do_resume(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_cli *cli; + + NV_INFO(drm, "re-enabling device...\n");
nouveau_agp_reset(drm);
@@ -491,6 +488,42 @@ nouveau_drm_resume(struct pci_dev *pdev) return 0; }
+int nouveau_pmops_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + int ret; + + if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) + return ret; + pci_set_master(pdev); + + return nouveau_do_resume(drm_dev); +} + +static int nouveau_pmops_freeze(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + return nouveau_do_suspend(drm_dev); +} + +static int nouveau_pmops_thaw(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + return nouveau_do_resume(drm_dev); +} + + static int nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) { @@ -643,14 +676,22 @@ nouveau_drm_pci_table[] = { {} };
+static const struct dev_pm_ops nouveau_pm_ops = { + .suspend = nouveau_pmops_suspend, + .resume = nouveau_pmops_resume, + .freeze = nouveau_pmops_freeze, + .thaw = nouveau_pmops_thaw, + .poweroff = nouveau_pmops_freeze, + .restore = nouveau_pmops_resume, +}; + static struct pci_driver nouveau_drm_pci_driver = { .name = "nouveau", .id_table = nouveau_drm_pci_table, .probe = nouveau_drm_probe, .remove = nouveau_drm_remove, - .suspend = nouveau_drm_suspend, - .resume = nouveau_drm_resume, + .driver.pm = &nouveau_pm_ops, };
static int __init diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 8194712..e0c99aa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -129,8 +129,8 @@ nouveau_dev(struct drm_device *dev) return nv_device(nouveau_drm(dev)->device); }
-int nouveau_drm_suspend(struct pci_dev *, pm_message_t); -int nouveau_drm_resume(struct pci_dev *); +int nouveau_pmops_suspend(struct device *); +int nouveau_pmops_resume(struct device *);
#define NV_FATAL(cli, fmt, args...) nv_fatal((cli), fmt, ##args) #define NV_ERROR(cli, fmt, args...) nv_error((cli), fmt, ##args) diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index 6f0ac64..25d3495 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -31,12 +31,11 @@ nouveau_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) { struct drm_device *dev = pci_get_drvdata(pdev); - pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) { printk(KERN_ERR "VGA switcheroo: switched nouveau on\n"); dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; - nouveau_drm_resume(pdev); + nouveau_pmops_resume(&pdev->dev); drm_kms_helper_poll_enable(dev); dev->switch_power_state = DRM_SWITCH_POWER_ON; } else { @@ -44,7 +43,7 @@ nouveau_switcheroo_set_state(struct pci_dev *pdev, dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; drm_kms_helper_poll_disable(dev); nouveau_switcheroo_optimus_dsm(); - nouveau_drm_suspend(pdev, pmm); + nouveau_pmops_suspend(&pdev->dev); dev->switch_power_state = DRM_SWITCH_POWER_OFF; } }
dri-devel@lists.freedesktop.org