From: Tejun Heo <htejun@gmail.com>
To: Greg KH <greg@kroah.com>
Cc: Jeff Garzik <jeff@garzik.org>,
linux-ide@vger.kernel.org,
owner-linux-pci@atrey.karlin.mff.cuni.cz
Subject: [PATCH 2/2] ata_piix: fix suspend/resume for some TOSHIBA laptops
Date: Wed, 11 Jul 2007 19:32:38 +0900 [thread overview]
Message-ID: <20070711103238.GF23568@htj.dyndns.org> (raw)
In-Reply-To: <20070711103204.GE23568@htj.dyndns.org>
ACPI implementations in several TOSHIBA laptops are weird and burn cpu
cycles for tens of seconds while trying to suspend if the PCI device
for the ATA controller is disabled when the ACPI suspend is called.
This patch uses DMI to match those machines and bypass device disable
on those machines during suspend. As the device needs to be put into
enabled state on resume without affecting PCI enable count, matching
resume callback uses pci_reenable_device().
This bug is reported in bugzilla bug 7780.
http://bugzilla.kernel.org/show_bug.cgi?id=7780
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
Updated to fit renamed pci_reenable_device().
drivers/ata/ata_piix.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/libata.h | 2
2 files changed, 113 insertions(+), 2 deletions(-)
Index: work/drivers/ata/ata_piix.c
===================================================================
--- work.orig/drivers/ata/ata_piix.c
+++ work/drivers/ata/ata_piix.c
@@ -91,6 +91,7 @@
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
+#include <linux/dmi.h>
#define DRV_NAME "ata_piix"
#define DRV_VERSION "2.11"
@@ -140,6 +141,9 @@ enum {
RV = -3, /* reserved */
PIIX_AHCI_DEVICE = 6,
+
+ /* host->flags bits */
+ PIIX_HOST_BROKEN_SUSPEND = (1 << 24),
};
struct piix_map_db {
@@ -159,6 +163,10 @@ static void piix_set_piomode (struct ata
static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
static int ich_pata_cable_detect(struct ata_port *ap);
+#ifdef CONFIG_PM
+static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+static int piix_pci_device_resume(struct pci_dev *pdev);
+#endif
static unsigned int in_module_init = 1;
@@ -253,8 +261,8 @@ static struct pci_driver piix_pci_driver
.probe = piix_init_one,
.remove = ata_pci_remove_one,
#ifdef CONFIG_PM
- .suspend = ata_pci_device_suspend,
- .resume = ata_pci_device_resume,
+ .suspend = piix_pci_device_suspend,
+ .resume = piix_pci_device_resume,
#endif
};
@@ -868,6 +876,107 @@ static void ich_set_dmamode (struct ata_
do_pata_set_dmamode(ap, adev, 1);
}
+#ifdef CONFIG_PM
+static struct dmi_system_id piix_broken_suspend_dmi_table[] = {
+ {
+ .ident = "TECRA M5",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M5"),
+ },
+ },
+ {
+ .ident = "Satellite U200",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U200"),
+ },
+ },
+ {
+ .ident = "Satellite U205",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U205"),
+ },
+ },
+ {
+ .ident = "Portege M500",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M500"),
+ },
+ },
+ { }
+};
+
+static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ unsigned long flags;
+ int rc = 0;
+
+ rc = ata_host_suspend(host, mesg);
+ if (rc)
+ return rc;
+
+ /* Some braindamaged ACPI suspend implementations expect the
+ * controller to be awake on entry; otherwise, it burns cpu
+ * cycles and power trying to do something to the sleeping
+ * beauty.
+ */
+ if (dmi_check_system(piix_broken_suspend_dmi_table) &&
+ mesg.event == PM_EVENT_SUSPEND) {
+ pci_save_state(pdev);
+
+ /* mark its power state as "unknown", since we don't
+ * know if e.g. the BIOS will change its device state
+ * when we suspend.
+ */
+ if (pdev->current_state == PCI_D0)
+ pdev->current_state = PCI_UNKNOWN;
+
+ /* tell resume that it's waking up from broken suspend */
+ spin_lock_irqsave(&host->lock, flags);
+ host->flags |= PIIX_HOST_BROKEN_SUSPEND;
+ spin_unlock_irqrestore(&host->lock, flags);
+ } else
+ ata_pci_device_do_suspend(pdev, mesg);
+
+ return 0;
+}
+
+static int piix_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ unsigned long flags;
+ int rc;
+
+ if (host->flags & PIIX_HOST_BROKEN_SUSPEND) {
+ spin_lock_irqsave(&host->lock, flags);
+ host->flags &= ~PIIX_HOST_BROKEN_SUSPEND;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ /* PCI device wasn't disabled during suspend. Use
+ * pci_reenable_device() to avoid unbalancing pdev
+ * enable count.
+ */
+ rc = pci_reenable_device(pdev);
+ if (rc)
+ dev_printk(KERN_ERR, &pdev->dev, "failed to enable "
+ "device after resume (%d)\n", rc);
+ } else
+ rc = ata_pci_device_do_resume(pdev);
+
+ if (rc == 0)
+ ata_host_resume(host);
+
+ return rc;
+}
+#endif
+
#define AHCI_PCI_BAR 5
#define AHCI_GLOBAL_CTL 0x04
#define AHCI_ENABLE (1 << 31)
Index: work/include/linux/libata.h
===================================================================
--- work.orig/include/linux/libata.h
+++ work/include/linux/libata.h
@@ -213,6 +213,8 @@ enum {
ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */
ATA_HOST_STARTED = (1 << 1), /* Host started */
+ /* bits 24:31 of host->flags are reserved for LLD specific flags */
+
/* various lengths of time */
ATA_TMOUT_BOOT = 30 * HZ, /* heuristic */
ATA_TMOUT_BOOT_QUICK = 7 * HZ, /* heuristic */
next prev parent reply other threads:[~2007-07-11 10:32 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-07-10 6:36 [PATCH 1/2] PCI: export __pci_reenable_device() Tejun Heo
2007-07-10 6:55 ` [PATCH 2/2] ata_piix: fix suspend/resume for some TOSHIBA laptops Tejun Heo
2007-07-24 20:59 ` Jeff Garzik
2007-07-24 21:57 ` Alan Cox
2007-07-24 22:05 ` Jeff Garzik
2007-07-27 5:43 ` [PATCH] pci: rename __pci_reenable_device() to pci_reenable_device() Tejun Heo
2007-07-27 5:53 ` [PATCH] ata_piix: implement piix_borken_suspend() Tejun Heo
2007-07-27 5:55 ` [PATCH] ata_piix: add Tecra M3 to broken suspend blacklist Tejun Heo
2007-07-27 6:22 ` [PATCH] pci: rename __pci_reenable_device() to pci_reenable_device() Greg KH
2007-08-01 14:02 ` Jeff Garzik
2007-07-10 16:17 ` [PATCH 1/2] PCI: export __pci_reenable_device() Greg KH
2007-07-11 10:32 ` [PATCH 1/2] PCI: rename and " Tejun Heo
2007-07-11 10:32 ` Tejun Heo [this message]
2007-07-17 17:05 ` Greg KH
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=20070711103238.GF23568@htj.dyndns.org \
--to=htejun@gmail.com \
--cc=greg@kroah.com \
--cc=jeff@garzik.org \
--cc=linux-ide@vger.kernel.org \
--cc=owner-linux-pci@atrey.karlin.mff.cuni.cz \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).