From: Stefan Demharter <stefan.demharter@gmx.net>
To: dri-devel@lists.freedesktop.org
Subject: [PATCH RFC v2] vga_switcheroo: restore mux and power states upon resume from hibernation.
Date: Fri, 31 Jan 2014 00:46:31 +0100 [thread overview]
Message-ID: <52EAE457.8010303@gmx.net> (raw)
Saves the current state of the mux and restores it upon resume from hibernation.
This is needed for muxed systems because the state of the mux doesn't survive a
hibernation-resume cycle. Furthermore also restores the power state of a GPU
to OFF after resume from hibernation if it was OFF before hibernation.
Signed-off-by: Stefan Demharter <stefan.demharter@gmx.net>
---
drivers/gpu/vga/vga_switcheroo.c | 96 +++++++++++++++++++++++++++++++++++-----
1 file changed, 85 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index ec0ae2d..85f41b9 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -28,6 +28,7 @@
#include <linux/console.h>
#include <linux/vga_switcheroo.h>
#include <linux/pm_runtime.h>
+#include <linux/suspend.h>
#include <linux/vgaarb.h>
@@ -72,6 +73,64 @@ static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
};
+#define MUX_STATE_UNDEFINED (-1)
+/*
+ * The next variable stores the state of the mux
+ * so it can be restored upon resume from hibernation.
+ */
+static int mux_state = MUX_STATE_UNDEFINED;
+
+static void vga_restore_mux(void)
+{
+ if (mux_state != MUX_STATE_UNDEFINED) {
+ int ret;
+ pr_info("vga_switcheroo: restoring mux state to %s\n",
+ mux_state == VGA_SWITCHEROO_IGD ? "IGD" : "DIS");
+
+ ret = vgasr_priv.handler->switchto(mux_state);
+ if (ret)
+ pr_warn("vga_switcheroo: mux switch failed (%d)\n", ret);
+ }
+}
+
+static void vga_restore_power_state(void)
+{
+ struct vga_switcheroo_client *client;
+
+ if (!vgasr_priv.handler->power_state)
+ return;
+
+ list_for_each_entry(client, &vgasr_priv.clients, list) {
+ if (client_is_vga(client) && client->pwr_state == VGA_SWITCHEROO_OFF) {
+ pr_info("vga_switcheroo: setting power state of %s to OFF\n",
+ client->id == VGA_SWITCHEROO_IGD ? "IGD" : "DIS");
+ vgasr_priv.handler->power_state(client->id, client->pwr_state);
+ }
+ }
+}
+
+/*
+ * Handle resume from hibernation:
+ * Restore mux state and power states for switcheroo controlled GPUs.
+ */
+static int vga_resume(struct notifier_block *nb, unsigned long action, void *unused)
+{
+ switch (action) {
+ case PM_POST_HIBERNATION:
+ mutex_lock(&vgasr_mutex);
+ vga_restore_mux();
+ vga_restore_power_state();
+ mutex_unlock(&vgasr_mutex);
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block vga_switcheroo_pm_nb = {
+ .notifier_call = vga_resume,
+ .priority = 0,
+};
+
static bool vga_switcheroo_ready(void)
{
/* we're ready if we get two clients + handler */
@@ -84,6 +143,8 @@ static void vga_switcheroo_enable(void)
int ret;
struct vga_switcheroo_client *client;
+ pr_info("vga_switcheroo: enabled\n");
+
/* call the handler to init */
if (vgasr_priv.handler->init)
vgasr_priv.handler->init();
@@ -99,6 +160,15 @@ static void vga_switcheroo_enable(void)
}
vga_switcheroo_debugfs_init(&vgasr_priv);
vgasr_priv.active = true;
+ register_pm_notifier(&vga_switcheroo_pm_nb);
+}
+
+void vga_switcheroo_disable(void)
+{
+ unregister_pm_notifier(&vga_switcheroo_pm_nb);
+ vgasr_priv.active = false;
+ vga_switcheroo_debugfs_fini(&vgasr_priv);
+ pr_info("vga_switcheroo: disabled\n");
}
int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
@@ -111,7 +181,6 @@ int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
vgasr_priv.handler = handler;
if (vga_switcheroo_ready()) {
- printk(KERN_INFO "vga_switcheroo: enabled\n");
vga_switcheroo_enable();
}
mutex_unlock(&vgasr_mutex);
@@ -124,9 +193,7 @@ void vga_switcheroo_unregister_handler(void)
mutex_lock(&vgasr_mutex);
vgasr_priv.handler = NULL;
if (vgasr_priv.active) {
- pr_info("vga_switcheroo: disabled\n");
- vga_switcheroo_debugfs_fini(&vgasr_priv);
- vgasr_priv.active = false;
+ vga_switcheroo_disable();
}
mutex_unlock(&vgasr_mutex);
}
@@ -155,7 +222,6 @@ static int register_client(struct pci_dev *pdev,
vgasr_priv.registered_clients++;
if (vga_switcheroo_ready()) {
- printk(KERN_INFO "vga_switcheroo: enabled\n");
vga_switcheroo_enable();
}
mutex_unlock(&vgasr_mutex);
@@ -235,9 +301,7 @@ void vga_switcheroo_unregister_client(struct pci_dev *pdev)
kfree(client);
}
if (vgasr_priv.active && vgasr_priv.registered_clients < 2) {
- printk(KERN_INFO "vga_switcheroo: disabled\n");
- vga_switcheroo_debugfs_fini(&vgasr_priv);
- vgasr_priv.active = false;
+ vga_switcheroo_disable();
}
mutex_unlock(&vgasr_mutex);
}
@@ -262,10 +326,11 @@ static int vga_switcheroo_show(struct seq_file *m, void *v)
int i = 0;
mutex_lock(&vgasr_mutex);
list_for_each_entry(client, &vgasr_priv.clients, list) {
- seq_printf(m, "%d:%s%s:%c:%s%s:%s\n", i,
+ seq_printf(m, "%d:%s%s:%c%s:%s%s:%s\n", i,
client_id(client) == VGA_SWITCHEROO_DIS ? "DIS" : "IGD",
client_is_vga(client) ? "" : "-Audio",
client->active ? '+' : ' ',
+ client_id(client) == mux_state ? "mux" : "",
client->driver_power_control ? "Dyn" : "",
client->pwr_state ? "Pwr" : "Off",
pci_name(client->pdev));
@@ -304,6 +369,15 @@ static int vga_switchoff(struct vga_switcheroo_client *client)
return 0;
}
+static int vga_switchto(int client_id)
+{
+ int ret = vgasr_priv.handler->switchto(client_id);
+
+ if (ret == 0)
+ mux_state = client_id;
+ return ret;
+}
+
static void set_audio_state(int id, int state)
{
struct vga_switcheroo_client *client;
@@ -353,7 +427,7 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
console_unlock();
}
- ret = vgasr_priv.handler->switchto(new_client->id);
+ ret = vga_switchto(new_client->id);
if (ret)
return ret;
@@ -468,7 +542,7 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
vgasr_priv.delayed_switch_active = false;
if (just_mux) {
- ret = vgasr_priv.handler->switchto(client_id);
+ ret = vga_switchto(client_id);
goto out;
}
--
1.8.5.3
next reply other threads:[~2014-01-30 23:47 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-01-30 23:46 Stefan Demharter [this message]
2014-01-31 14:32 ` [PATCH RFC v2] vga_switcheroo: restore mux and power states upon resume from hibernation Alex Deucher
2014-09-05 11:28 ` Jani Nikula
2014-09-26 22:32 ` Stefan Demharter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52EAE457.8010303@gmx.net \
--to=stefan.demharter@gmx.net \
--cc=dri-devel@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.