From patchwork Thu Jan 30 23:46:31 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Demharter X-Patchwork-Id: 3559761 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 6F498C02DC for ; Thu, 30 Jan 2014 23:47:23 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 78FB9201B9 for ; Thu, 30 Jan 2014 23:47:22 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 2FCA12010E for ; Thu, 30 Jan 2014 23:47:21 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 48457106E95; Thu, 30 Jan 2014 15:47:19 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mout.gmx.net (mout.gmx.net [212.227.17.21]) by gabe.freedesktop.org (Postfix) with ESMTP id 6A33444481 for ; Thu, 30 Jan 2014 15:47:12 -0800 (PST) Received: from [192.168.179.20] ([80.137.121.240]) by mail.gmx.com (mrgmx101) with ESMTPSA (Nemesis) id 0LsPwa-1V6zbB1aMC-011yrf for ; Fri, 31 Jan 2014 00:47:09 +0100 Message-ID: <52EAE457.8010303@gmx.net> Date: Fri, 31 Jan 2014 00:46:31 +0100 From: Stefan Demharter User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.2.0 MIME-Version: 1.0 To: dri-devel@lists.freedesktop.org Subject: [PATCH RFC v2] vga_switcheroo: restore mux and power states upon resume from hibernation. X-Provags-ID: V03:K0:x0elIlIYjFvDRFAgCH65cNH3jGhEleuFAqAAj/b2w+/wNNoYDBo gKDlAbehN+hupt8jEu1ltiMNLVCiuiahZscGYoSrvueNj02jc1MTpFFfFB+NT89BwCsMZ3h mVUy6gsz86yRiuEZIFxJuisvh8Szsa/15+okkH4exH4GXkmlIO1cLtO/y+cQa4EZerWvmFv xdkOlrqG6/nRMvnP/Ve6A== X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dri-devel-bounces@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org X-Spam-Status: No, score=-4.6 required=5.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 Reviewed-by: Alex Deucher --- 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 #include #include +#include #include @@ -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; }