On Tue, 26 Feb 2008 11:26:53 +0100 Pavel Machek wrote: Hi Pavel, Is this limited to UP and only one disk? [comments below] > Sleepy linux support, demo version, but it works on my thinkpad x60 ;-). > > Signed-off-by: Pavel Machek <pavel@xxxxxxx> > > diff --git a/Documentation/power/sleepy.txt b/Documentation/power/sleepy.txt > new file mode 100644 > index 0000000..a9caf05 > --- /dev/null > +++ b/Documentation/power/sleepy.txt > @@ -0,0 +1,55 @@ > + Sleepy Linux > + ~~~~~~~~~~~~ > + > +Copyright 2007 Pavel Machek <pavel@xxxxxxx> > + GPLv2 > + > +Current Linux versions can enter suspend-to-RAM just fine, but only > +can do it on explicit request. But suspend-to-RAM is important, eating Usually "can only do it" AFAIK. > +something like 10% of power needed for idle system. Starting suspend > +manually is not too convinient; it is not an option on multiuser convenient; > +machine, and even on single user machine, some things are not easy: > + > +1) Download this big chunk in mozilla, then go to sleep > + > +2) Compile this, then go to sleep > + > +3) You can sleep now, but wake me up in 8:30 with mp3 player > + > +Todays hardware is mostly capable of doing better: with correctly set Today's > +up wakeups, machine can sleep and successfully pretend it is not > +sleeping -- by waking up whenever something interesting happens. Of > +course, it is easier on machines not connected to the network, and on > +notebook computers. > + > +Requirements: > + > +0) Working suspend-to-RAM, with kernel being able to bring video back. > + > +1) RTC clock that can wake up system > + > +2) Lid that can wake up a system, > + or keyboard that can wake up system and does not loose keypress lose > + or special screensaver setup > + > +3) Network card that is either down > + or can wake up system on any packet (and not loose too many packets) lose > + > +How to use it > +~~~~~~~~~~~~~ > + > +First, make sure your config is tiny enough that cpu sleeps at least CPU (please) > +five or so seconds between wakeups. You'll probably need to disable > +USB, make some kernel timers way longer than default and boot with > +init=/bin/bash. > + > +Then, enable SCSI powersave by something like: > + > +mount /sys Isn't /sys auto-mounted by kernel? > +echo auto > /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/power/level > +echo 3 > /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/power/autosuspend > +echo adisk > /sys/power/state > +mount / -oremount,commit=900 > + > +Then, echo auto > /sys/power/state should enable sleepy support. Do it > +twice, and it will ignore open lid and sleep anyway. > diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c > index 29e71bd..0197b1f 100644 > --- a/drivers/ata/ahci.c > +++ b/drivers/ata/ahci.c > @@ -268,6 +269,41 @@ static struct class_device_attribute *ah > NULL > }; > > +struct pci_dev *my_pdev; > +int autosuspend_enabled; > + > +struct sleep_disabled_reason ahci_active = { > + "ahci" > +}; > + > +/* The host and its devices are all idle so we can autosuspend */ > +static int autosuspend(struct Scsi_Host *host) > +{ > + if (my_pdev && autosuspend_enabled) { > + printk("ahci: should autosuspend\n"); Use printk() KERN_* levels (multiple places). > + ahci_pci_device_suspend(my_pdev, PMSG_SUSPEND); > + enable_auto_sleep(&ahci_active); > + return 0; > + } > + printk("ahci: autosuspend disabled\n"); > + return -EINVAL; > +} > + ... > +} > + > + > + > static struct scsi_host_template ahci_sht = { > .module = THIS_MODULE, > .name = DRV_NAME, > @@ -1820,6 +1858,10 @@ static void ahci_thaw(struct ata_port *a > > static void ahci_error_handler(struct ata_port *ap) > { > + struct ata_host *host = ap->host; > + int rc; > + extern int slept; Eh? > + > if (!(ap->pflags & ATA_PFLAG_FROZEN)) { > /* restart engine */ > ahci_stop_engine(ap); General comment: Lots of the comment fixes in libata should be part of a standalone patch, not part of this patch. > diff --git a/include/linux/ata.h b/include/linux/ata.h > index 78bbaca..df2dd4f 100644 > --- a/include/linux/ata.h > +++ b/include/linux/ata.h > @@ -298,6 +298,13 @@ enum { > SCR_ACTIVE = 3, > SCR_NOTIFICATION = 4, > > + /* SControl subfields, each field is 4 bit wide */ bits > + ATA_SCTL_DET = 0, /* lsb */ > + ATA_SCTL_SPD = 1, > + ATA_SCTL_IPM = 2, > + ATA_SCTL_SPM = 3, > + ATA_SCTL_PMP = 4, > + > /* SError bits */ > SERR_DATA_RECOVERED = (1 << 0), /* recovered data error */ > SERR_COMM_RECOVERED = (1 << 1), /* recovered comm failure */ > diff --git a/kernel/power/main.c b/kernel/power/main.c > index a29da58..2470e94 100644 > --- a/kernel/power/main.c > +++ b/kernel/power/main.c > @@ -3,6 +3,7 @@ > * > * Copyright (c) 2003 Patrick Mochel > * Copyright (c) 2003 Open Source Development Lab > + * Copyright (c) 2007 Pavel Machek <pavel@xxxxxxx> It's 2008 now. > * > * This file is released under the GPLv2 > * > @@ -22,7 +23,10 @@ #include <linux/freezer.h> > #include <linux/vmstat.h> > #include <linux/syscalls.h> > > +#include <asm/percpu.h> > + > #include "power.h" > +#include "../../drivers/scsi/scsi_priv.h" ugh. > DEFINE_MUTEX(pm_mutex); > > @@ -426,6 +437,76 @@ static int enter_state(suspend_state_t s > return error; > } > > +/* Returns how long it waited in ms */ > +//extern long (*panic_blink)(long time); > + > +int slept; > + > + > +struct sleep_disabled_reason wakeup_tasks = { > + "wakeup_tasks" > +}; > + > +int device_suspend_fake(pm_message_t state); > + > +int > +do_auto_sleep(void) All on one line. > +{ > + int error,i; space after comma. > + int state = PM_SUSPEND_MEM; > + > + /* add baby "morning tasks" to the lists. BUG if it is not > + the only baby */ > + > + if (slept) > + return; > + slept++; > + disable_auto_sleep(&wakeup_tasks); > +// device_suspend_fake(PMSG_SUSPEND); > + suspend_enter(state); > + > + /* FIXME: run "morning tasks" in process context; drivers need to check why > + machine was woken, and perhaps put themselves back to crying babies list > + if lid was opened or something. */ > + > + enable_auto_sleep(&wakeup_tasks); > + > +#if 0 > + printk("finishing\n"); > + if (suspend_ops->finish) > + suspend_ops->finish(); > +#endif > + > + return 0; > +} > + > +extern int set_alarm(int length); > + > +void > +enter_auto_sleep(int length) All on one line. > +{ > + int error; > + > + if (atomic_read(&cpu_needed)) > + return; > + > + printk("Auto sleeping\n"); > + set_alarm(length); > + > + error = do_auto_sleep(); > + if (error) > + printk("enter auto sleep failed: %d\n", error); > +} > > /** > * pm_suspend - Externally visible function for suspending system. > @@ -481,6 +562,12 @@ #endif > return (s - buf); > } > > +extern struct pci_dev *my_pdev; > +extern int autosuspend_enabled; > +extern struct device *my_scsi_disk; > +extern int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); > +extern int ahci_pci_device_resume(struct pci_dev *pdev); > + Externs in header files, please. > static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, > const char *buf, size_t n) > { ... --- ~Randy _______________________________________________ linux-pm mailing list linux-pm@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/linux-pm