From patchwork Fri Sep 25 23:26:48 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Wysocki X-Patchwork-Id: 50198 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n8PNQhSV016143 for ; Fri, 25 Sep 2009 23:26:43 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750926AbZIYXZt (ORCPT ); Fri, 25 Sep 2009 19:25:49 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752787AbZIYXZs (ORCPT ); Fri, 25 Sep 2009 19:25:48 -0400 Received: from ogre.sisk.pl ([217.79.144.158]:54675 "EHLO ogre.sisk.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750926AbZIYXZq (ORCPT ); Fri, 25 Sep 2009 19:25:46 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by ogre.sisk.pl (Postfix) with ESMTP id A31D715AD1E; Fri, 25 Sep 2009 22:17:07 +0200 (CEST) Received: from ogre.sisk.pl ([127.0.0.1]) by localhost (ogre.sisk.pl [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 22695-06; Fri, 25 Sep 2009 22:16:42 +0200 (CEST) Received: from tosh.localnet (220-bem-13.acn.waw.pl [82.210.184.220]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ogre.sisk.pl (Postfix) with ESMTP id BDD8515AD46; Fri, 25 Sep 2009 22:16:41 +0200 (CEST) From: "Rafael J. Wysocki" To: pm list Subject: [PATCH 2/2] PM / yenta: Fix cardbus suspend/resume regression Date: Sat, 26 Sep 2009 01:26:48 +0200 User-Agent: KMail/1.12.1 (Linux/2.6.31-rjw; KDE/4.3.1; x86_64; ; ) Cc: LKML , Linux PCI , Jesse Barnes , ACPI Devel Maling List , linux-pcmcia@lists.infradead.org, Andrew Morton , Florian References: <200909260122.59030.rjw@sisk.pl> In-Reply-To: <200909260122.59030.rjw@sisk.pl> MIME-Version: 1.0 Message-Id: <200909260126.48896.rjw@sisk.pl> X-Virus-Scanned: amavisd-new at ogre.sisk.pl using MkS_Vir for Linux Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: Rafael J. Wysocki Since 2.6.29 the PCI PM core have been restoring the standard configuration registers of PCI devices in the early phase of resume. In particular, PCI devices without drivers have been handled this way since commit 355a72d75b3b4f4877db4c9070c798238028ecb5 (PCI: Rework default handling of suspend and resume). Unfortunately, this leads to post-resume problems with CardBus devices which cannot be accessed in the early phase of resume, because the sockets they are on have not been woken up yet at that point. To solve this problem, move the yenta socket resume to the early phase of resume and, analogously, move the suspend of it to the late phase of suspend. Additionally, remove some unnecessary PCI code from the yenta socket's resume routine. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=13092, which is a post-2.6.28 regression. Signed-off-by: Rafael J. Wysocki Reported-by: Florian --- drivers/pcmcia/yenta_socket.c | 92 ++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 42 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Index: linux-2.6-stable/drivers/pcmcia/yenta_socket.c =================================================================== --- linux-2.6-stable.orig/drivers/pcmcia/yenta_socket.c +++ linux-2.6-stable/drivers/pcmcia/yenta_socket.c @@ -1225,60 +1225,71 @@ static int __devinit yenta_probe (struct } #ifdef CONFIG_PM -static int yenta_dev_suspend (struct pci_dev *dev, pm_message_t state) +static int yenta_dev_suspend_noirq(struct device *dev) { - struct yenta_socket *socket = pci_get_drvdata(dev); + struct pci_dev *pdev = to_pci_dev(dev); + struct yenta_socket *socket = pci_get_drvdata(pdev); int ret; - ret = pcmcia_socket_dev_suspend(&dev->dev, state); + ret = pcmcia_socket_dev_suspend(dev); - if (socket) { - if (socket->type && socket->type->save_state) - socket->type->save_state(socket); - - /* FIXME: pci_save_state needs to have a better interface */ - pci_save_state(dev); - pci_read_config_dword(dev, 16*4, &socket->saved_state[0]); - pci_read_config_dword(dev, 17*4, &socket->saved_state[1]); - pci_disable_device(dev); - - /* - * Some laptops (IBM T22) do not like us putting the Cardbus - * bridge into D3. At a guess, some other laptop will - * probably require this, so leave it commented out for now. - */ - /* pci_set_power_state(dev, 3); */ - } + if (!socket) + return ret; + + if (socket->type && socket->type->save_state) + socket->type->save_state(socket); + + pci_save_state(pdev); + pci_read_config_dword(pdev, 16*4, &socket->saved_state[0]); + pci_read_config_dword(pdev, 17*4, &socket->saved_state[1]); + pci_disable_device(pdev); + + /* + * Some laptops (IBM T22) do not like us putting the Cardbus + * bridge into D3. At a guess, some other laptop will + * probably require this, so leave it commented out for now. + */ + /* pci_set_power_state(dev, 3); */ return ret; } - -static int yenta_dev_resume (struct pci_dev *dev) +static int yenta_dev_resume_noirq(struct device *dev) { - struct yenta_socket *socket = pci_get_drvdata(dev); + struct pci_dev *pdev = to_pci_dev(dev); + struct yenta_socket *socket = pci_get_drvdata(pdev); + int ret; - if (socket) { - int rc; + if (!socket) + return 0; - pci_set_power_state(dev, 0); - /* FIXME: pci_restore_state needs to have a better interface */ - pci_restore_state(dev); - pci_write_config_dword(dev, 16*4, socket->saved_state[0]); - pci_write_config_dword(dev, 17*4, socket->saved_state[1]); + pci_write_config_dword(pdev, 16*4, socket->saved_state[0]); + pci_write_config_dword(pdev, 17*4, socket->saved_state[1]); - rc = pci_enable_device(dev); - if (rc) - return rc; + ret = pci_enable_device(pdev); + if (ret) + return ret; - pci_set_master(dev); + pci_set_master(pdev); - if (socket->type && socket->type->restore_state) - socket->type->restore_state(socket); - } + if (socket->type && socket->type->restore_state) + socket->type->restore_state(socket); - return pcmcia_socket_dev_resume(&dev->dev); + return pcmcia_socket_dev_resume(dev); } + +static struct dev_pm_ops yenta_pm_ops = { + .suspend_noirq = yenta_dev_suspend_noirq, + .resume_noirq = yenta_dev_resume_noirq, + .freeze_noirq = yenta_dev_suspend_noirq, + .thaw_noirq = yenta_dev_resume_noirq, + .poweroff_noirq = yenta_dev_suspend_noirq, + .restore_noirq = yenta_dev_resume_noirq, +}; + +#define YENTA_PM_OPS (¥ta_pm_ops) +#else +#define YENTA_PM_OPS NULL #endif #define CB_ID(vend,dev,type) \ @@ -1376,10 +1387,7 @@ static struct pci_driver yenta_cardbus_d .id_table = yenta_table, .probe = yenta_probe, .remove = __devexit_p(yenta_close), -#ifdef CONFIG_PM - .suspend = yenta_dev_suspend, - .resume = yenta_dev_resume, -#endif + .driver.pm = YENTA_PM_OPS, };