some problems in suspend/resume on ThinkPad X61

Takanori Watanabe takawata at init-main.com
Mon Apr 7 15:52:59 UTC 2008


I bought a new laptop;ThinkPad X61 and I'm trying to hack 
suspend/resume.

As the first step, I'm trying to make sure to suspend/resume work
in uniprocessor kernel.

Finally I did succeeded to suspend and resume with
1) fwohci disabled
2) if_em down
3) hw.acpi.reset_video=1
4) modify ata driver with following crude patch.
(Not generic solution.)

So I want ata_pci_controller->chipinit and ata_pci_controller->allocate
should split into two parts:Hardware initialization and 
data structure initialization.


--- ata-chipset.c.~1.212.~	2008-03-07 09:29:19.000000000 +0000
+++ ata-chipset.c	2008-04-08 00:23:34.000000000 +0000
@@ -540,7 +540,37 @@
 		  (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1);
     return 0;
 }
+void ata_ahci_tell_dma(device_t dev);
+void ata_ahci_tell_dma(device_t dev)
+{
+    struct ata_pci_controller *ctlr;
+    struct ata_channel *ch = device_get_softc(dev);
+    u_int64_t work;
+    int offset = ch->unit << 7;
+
+    ctlr = device_get_softc(device_get_parent(dev));
+    /* setup work areas */
+    work = ch->dma->work_bus + ATA_AHCI_CL_OFFSET;
+    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff);
+    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32);
+
+    work = ch->dma->work_bus + ATA_AHCI_FB_OFFSET;
+    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff); 
+    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32);
 
+    /* enable wanted port interrupts */
+    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset,
+	     (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
+	      ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
+	      ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP |
+	      ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS |
+	      ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR));
+
+    /* start operations on this channel */
+    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+	     (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE |
+	      ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST));
+}
 static int
 ata_ahci_allocate(device_t dev)
 {
--- ata-pci.c.~1.123.~	2007-11-18 14:44:52.000000000 +0000
+++ ata-pci.c	2008-04-07 23:25:04.000000000 +0000
@@ -48,6 +48,7 @@
 #include <dev/ata/ata-all.h>
 #include <dev/ata/ata-pci.h>
 #include <ata_if.h>
+extern void ata_ahci_tell_dma(device_t dev);
 
 /* local vars */
 static MALLOC_DEFINE(M_ATAPCI, "ata_pci", "ATA driver PCI");
@@ -186,6 +187,18 @@
     return ENXIO;
 }
 
+static int ata_pci_resume(device_t dev)
+{
+	struct ata_pci_controller *ctlr = device_get_softc(dev);
+	int chans = ctlr->channels;
+	ctlr->chipinit(dev);
+
+	if(chans != ctlr->channels){
+		device_printf(dev, "WARNING: channel number changed\n");
+	}
+
+	return bus_generic_resume(dev);
+}
 int
 ata_pci_attach(device_t dev)
 {
@@ -546,7 +559,7 @@
     DEVMETHOD(device_detach,            ata_pci_detach),
     DEVMETHOD(device_shutdown,          bus_generic_shutdown),
     DEVMETHOD(device_suspend,           bus_generic_suspend),
-    DEVMETHOD(device_resume,            bus_generic_resume),
+    DEVMETHOD(device_resume,            ata_pci_resume),
 
     /* bus methods */
     DEVMETHOD(bus_alloc_resource,       ata_pci_alloc_resource),
@@ -678,6 +691,15 @@
 	ctlr->setmode(dev, mode);
 }
 
+static int  ata_pcichannel_resume(device_t dev)
+{
+	struct ata_channel *ch = device_get_softc(dev);
+	struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+	if(ch->dma&&ctlr->r_res2)
+		ata_ahci_tell_dma(dev);
+
+	return ata_resume(dev);
+}
 static device_method_t ata_pcichannel_methods[] = {
     /* device interface */
     DEVMETHOD(device_probe,     ata_pcichannel_probe),
@@ -685,7 +707,7 @@
     DEVMETHOD(device_detach,    ata_pcichannel_detach),
     DEVMETHOD(device_shutdown,  bus_generic_shutdown),
     DEVMETHOD(device_suspend,   ata_suspend),
-    DEVMETHOD(device_resume,    ata_resume),
+    DEVMETHOD(device_resume,    ata_pcichannel_resume),
 
     /* ATA methods */
     DEVMETHOD(ata_setmode,      ata_pcichannel_setmode),



More information about the freebsd-acpi mailing list