On Thu, Apr 29, 2004 at 09:21:06AM +0200, Arne Caspari wrote:
> I am using kernel 2.6.5 on an iBook G4. Is there any way to get this machine 
> into any suspend mode?
Could you try the attached patch, it should allow for suspend to disk.
Cheers,
 -- Guido
Index: kernel/sys.c
===================================================================
--- kernel/sys.c        (revision 26)
+++ kernel/sys.c        (working copy)
@@ -84,7 +84,7 @@
  *     and the like. 
  */
 
-static struct notifier_block *reboot_notifier_list;
+struct notifier_block *reboot_notifier_list;
 rwlock_t notifier_lock = RW_LOCK_UNLOCKED;
 
 /**
Index: kernel/power/main.c
===================================================================
--- kernel/power/main.c (revision 26)
+++ kernel/power/main.c (working copy)
@@ -120,6 +120,7 @@
 
 char * pm_states[] = {
        [PM_SUSPEND_STANDBY]    = "standby",
+       [2]                     = "",
        [PM_SUSPEND_MEM]        = "mem",
        [PM_SUSPEND_DISK]       = "disk",
        NULL,
Index: kernel/power/pmdisk.c
===================================================================
--- kernel/power/pmdisk.c       (revision 26)
+++ kernel/power/pmdisk.c       (working copy)
@@ -18,7 +18,7 @@
  *
  */
 
-#undef DEBUG
+#define DEBUG
 
 #include <linux/mm.h>
 #include <linux/bio.h>
@@ -569,7 +572,7 @@
 
 
 /**
- *     enough_free_mem - Make sure we enough free memory to snapshot.
+ *     enough_free_mem - Make sure we have enough free memory to snapshot.
  *
  *     Returns TRUE or FALSE after checking the number of available 
  *     free pages.
@@ -625,8 +628,10 @@
 {
        int error = 0;
 
-       if ((error = read_swapfiles()))
+       if ((error = read_swapfiles())) {
+               printk("Can't read swapfiles\n");
                return error;
+       }
 
        drain_local_pages();
 
@@ -703,6 +709,7 @@
  * Magic happens here
  */
 
+#if 0
 int pmdisk_resume(void)
 {
        BUG_ON (nr_copy_pages_check != pmdisk_pages);
@@ -712,6 +719,7 @@
        __flush_tlb_global();
        return 0;
 }
+#endif
 
 /* pmdisk_arch_suspend() is implemented in arch/?/power/pmdisk.S,
    and basically does:
@@ -1083,9 +1091,11 @@
        if ((error = arch_prepare_suspend()))
                return error;
        local_irq_disable();
+       device_power_down(PM_SUSPEND_DISK);
        save_processor_state();
        error = pmdisk_arch_suspend(0);
        restore_processor_state();
+       device_power_up();
        local_irq_enable();
        return error;
 }
@@ -1144,10 +1154,13 @@
 int __init pmdisk_restore(void)
 {
        int error;
+
        local_irq_disable();
+       device_power_down(PM_SUSPEND_DISK);
        save_processor_state();
        error = pmdisk_arch_suspend(1);
        restore_processor_state();
+       device_power_up();
        local_irq_enable();
        return error;
 }
Index: kernel/power/disk.c
===================================================================
--- kernel/power/disk.c (revision 26)
+++ kernel/power/disk.c (working copy)
@@ -17,6 +17,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
+#include <linux/reboot.h>
 #include "power.h"
 
 
@@ -45,23 +46,26 @@
        unsigned long flags;
        int error = 0;
 
-       local_irq_save(flags);
-       device_power_down(PM_SUSPEND_DISK);
        switch(mode) {
        case PM_DISK_PLATFORM:
+               local_irq_save(flags);
                error = pm_ops->enter(PM_SUSPEND_DISK);
+               local_irq_restore(flags);
                break;
        case PM_DISK_SHUTDOWN:
                printk("Powering off system\n");
+               notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
+               device_shutdown();
                machine_power_off();
                break;
        case PM_DISK_REBOOT:
+               printk("Rebooting system\n");
+               notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+               device_shutdown();
                machine_restart(NULL);
                break;
        }
        machine_halt();
-       device_power_up();
-       local_irq_restore(flags);
        return 0;
 }
 
@@ -162,8 +166,10 @@
 
        pr_debug("PM: snapshotting memory.\n");
        in_suspend = 1;
-       if ((error = pmdisk_save()))
+       if ((error = pmdisk_save())) {
+               pr_debug("PM: snapshot memory failed !\n");
                goto Done;
+       }
 
        if (in_suspend) {
                pr_debug("PM: writing image.\n");
@@ -224,9 +230,6 @@
         * Do it with disabled interrupts for best effect. That way, if some
         * driver scheduled DMA, we have good chance for DMA to finish ;-).
         */
-       pr_debug("PM: Waiting for DMAs to settle down.\n");
-       mdelay(1000);
-
        pr_debug("PM: Restoring saved image.\n");
        pmdisk_restore();
        pr_debug("PM: Restore failed, recovering.n");
Index: include/linux/pm.h
===================================================================
--- include/linux/pm.h  (revision 26)
+++ include/linux/pm.h  (working copy)
@@ -195,10 +195,10 @@
 extern void (*pm_power_off)(void);
 
 enum {
-       PM_SUSPEND_ON,
-       PM_SUSPEND_STANDBY,
-       PM_SUSPEND_MEM,
-       PM_SUSPEND_DISK,
+       PM_SUSPEND_ON = 0,
+       PM_SUSPEND_STANDBY = 1,
+       PM_SUSPEND_MEM = 3,
+       PM_SUSPEND_DISK = 4,
        PM_SUSPEND_MAX,
 };
 
Index: include/linux/suspend.h
===================================================================
--- include/linux/suspend.h     (revision 26)
+++ include/linux/suspend.h     (working copy)
@@ -1,9 +1,9 @@
 #ifndef _LINUX_SWSUSP_H
 #define _LINUX_SWSUSP_H
 
-#ifdef CONFIG_X86
+//#ifdef CONFIG_X86
 #include <asm/suspend.h>
-#endif
+//#endif
 #include <linux/swap.h>
 #include <linux/notifier.h>
 #include <linux/config.h>
Index: include/linux/reboot.h
===================================================================
--- include/linux/reboot.h      (revision 26)
+++ include/linux/reboot.h      (working copy)
@@ -40,6 +40,8 @@
 extern int register_reboot_notifier(struct notifier_block *);
 extern int unregister_reboot_notifier(struct notifier_block *);
 
+/* For use by swsusp only */
+extern struct notifier_block *reboot_notifier_list;
 
 /*
  * Architecture-specific implementations of sys_reboot commands.
Index: arch/ppc/kernel/Makefile
===================================================================
--- arch/ppc/kernel/Makefile    (revision 26)
+++ arch/ppc/kernel/Makefile    (working copy)
@@ -15,6 +15,7 @@
 extra-$(CONFIG_8xx)            := head_8xx.o
 extra-$(CONFIG_6xx)            += idle_6xx.o
 extra-$(CONFIG_POWER4)         += idle_power4.o
+
 extra-y                                += vmlinux.lds.s
 
 obj-y                          := entry.o traps.o irq.o idle.o time.o misc.o \
@@ -22,6 +23,7 @@
                                        semaphore.o syscalls.o setup.o \
                                        cputable.o ppc_htab.o
 obj-$(CONFIG_6xx)              += l2cr.o cpu_setup_6xx.o
+obj-$(CONFIG_PM_DISK)          += pmdisk.o
 obj-$(CONFIG_POWER4)           += cpu_setup_power4.o
 obj-$(CONFIG_MODULES)          += module.o ppc_ksyms.o
 obj-$(CONFIG_PCI)              += pci.o
Index: arch/ppc/kernel/vmlinux.lds.S
===================================================================
--- arch/ppc/kernel/vmlinux.lds.S       (revision 26)
+++ arch/ppc/kernel/vmlinux.lds.S       (working copy)
@@ -72,6 +72,12 @@
     CONSTRUCTORS
   }
 
+  . = ALIGN(4096);
+  __nosave_begin = .;
+  .data_nosave : { *(.data.nosave) }
+  . = ALIGN(4096);
+  __nosave_end = .;
+
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
Index: arch/ppc/kernel/signal.c
===================================================================
--- arch/ppc/kernel/signal.c    (revision 26)
+++ arch/ppc/kernel/signal.c    (working copy)
@@ -28,6 +28,7 @@
 #include <linux/elf.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
+#include <linux/suspend.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -569,6 +570,11 @@
        unsigned long frame, newsp;
        int signr, ret;
 
+       if (current->flags & PF_FREEZE) {
+               refrigerator(0);
+               return 0;
+       }
+
        if (!oldset)
                oldset = &current->blocked;
 
Index: arch/ppc/Kconfig
===================================================================
--- arch/ppc/Kconfig    (revision 26)
+++ arch/ppc/Kconfig    (working copy)
@@ -914,6 +914,8 @@
 
 source "drivers/zorro/Kconfig"
 
+source kernel/power/Kconfig
+
 endmenu
 
 menu "Bus options"
Index: arch/ppc/platforms/pmac_setup.c
===================================================================
--- arch/ppc/platforms/pmac_setup.c     (revision 26)
+++ arch/ppc/platforms/pmac_setup.c     (working copy)
@@ -51,6 +51,7 @@
 #include <linux/irq.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
+#include <linux/suspend.h>
 
 #include <asm/reg.h>
 #include <asm/sections.h>
@@ -70,6 +71,8 @@
 #include <asm/pmac_feature.h>
 #include <asm/time.h>
 #include <asm/of_device.h>
+#include <asm/mmu_context.h>
+
 #include "pmac_pic.h"
 #include "mem_pieces.h"
 
@@ -425,11 +428,65 @@
 #endif
 }
 
+/* TODO: Merge the suspend-to-ram with the common code !!!
+ * currently, this is a stub implementation for suspend-to-disk
+ * only
+ */
+
+#ifdef CONFIG_PM_DISK
+
+static int pmac_pm_prepare(u32 state)
+{
+       printk(KERN_DEBUG "pmac_pm_prepare(%d)\n", state);
+
+       return 0;
+}
+
+static int pmac_pm_enter(u32 state)
+{
+       printk(KERN_DEBUG "pmac_pm_enter(%d)\n", state);
+
+       /* Giveup the lazy FPU & vec so we don't have to back them
+        * up from the low level code
+        */
+       enable_kernel_fp();
+
+#ifdef CONFIG_ALTIVEC
+       if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC)
+               enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+       return 0;
+}
+
+static int pmac_pm_finish(u32 state)
+{
+       printk(KERN_DEBUG "pmac_pm_finish(%d)\n", state);
+
+       /* Restore userland MMU context */
+       set_context(current->active_mm->context, current->active_mm->pgd);
+
+       return 0;
+}
+
+static struct pm_ops pmac_pm_ops = {
+       .pm_disk_mode   = PM_DISK_SHUTDOWN,
+       .prepare        = pmac_pm_prepare,
+       .enter          = pmac_pm_enter,
+       .finish         = pmac_pm_finish,
+};
+
+#endif /* CONFIG_PM_DISK */
+
 static int initializing = 1;
 
 static int pmac_late_init(void)
 {
        initializing = 0;
+
+#ifdef CONFIG_PM_DISK
+       pm_set_ops(&pmac_pm_ops);
+#endif /* CONFIG_PM_DISK */
        return 0;
 }
 
Index: arch/ppc/platforms/pmac_feature.c
===================================================================
--- arch/ppc/platforms/pmac_feature.c   (revision 26)
+++ arch/ppc/platforms/pmac_feature.c   (working copy)
@@ -1156,7 +1156,7 @@
                        (void)MACIO_IN32(KEYLARGO_FCR1);
                        mdelay(1);
                        LOCK(flags);
-                       MACIO_BIS(KEYLARGO_FCR0, KL1_USB2_CELL_ENABLE);
+                       MACIO_BIS(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE);
                }
                if (number < 4) {
                        reg = MACIO_IN32(KEYLARGO_FCR4);
Index: drivers/video/aty/radeon_pm.c
===================================================================
--- drivers/video/aty/radeon_pm.c       (revision 26)
+++ drivers/video/aty/radeon_pm.c       (working copy)
@@ -846,6 +846,8 @@
         */
 
        printk(KERN_DEBUG "radeonfb: suspending to state: %d...\n", state);
+       if (state != 2 && state != 3)
+               return 0;
        
        if (pdev->dev.power_state >= state)
                return 0;
Index: drivers/macintosh/Kconfig
===================================================================
--- drivers/macintosh/Kconfig   (revision 26)
+++ drivers/macintosh/Kconfig   (working copy)
@@ -80,7 +80,7 @@
 
 config PMAC_PBOOK
        bool "Power management support for PowerBooks"
-       depends on ADB_PMU
+       depends on PM && ADB_PMU
        ---help---
          This provides support for putting a PowerBook to sleep; it also
          enables media bay support.  Power management works on the
@@ -97,10 +97,10 @@
          have it autoloaded. The act of removing the module shuts down the
          sound hardware for more power savings.
 
-config PM
-       bool
-       depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
-       default y
+#config PM
+#      bool
+#      depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
+#      default y
 
 config PMAC_APM_EMU
        tristate "APM emulation"
Index: drivers/macintosh/mediabay.c
===================================================================
--- drivers/macintosh/mediabay.c        (revision 26)
+++ drivers/macintosh/mediabay.c        (working copy)
@@ -715,7 +715,7 @@
 {
        struct media_bay_info   *bay = macio_get_drvdata(mdev);
 
-       if (state != mdev->ofdev.dev.power_state && state >= 2) {
+       if (state != mdev->ofdev.dev.power_state && state >= 2 && state != 4) {
                down(&bay->lock);
                bay->sleeping = 1;
                set_mb_power(bay, 0);
Index: drivers/macintosh/via-pmu.c
===================================================================
--- drivers/macintosh/via-pmu.c (revision 26)
+++ drivers/macintosh/via-pmu.c (working copy)
@@ -43,6 +43,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
+#include <linux/sysdev.h>
 #include <linux/suspend.h>
 #include <linux/syscalls.h>
 #include <asm/prom.h>
@@ -2324,7 +2325,7 @@
        /* Sync the disks. */
        /* XXX It would be nice to have some way to ensure that
         * nobody is dirtying any new buffers while we wait. That
-        * could be acheived using the refrigerator for processes
+        * could be achieved using the refrigerator for processes
         * that swsusp uses
         */
        sys_sync();
@@ -2377,7 +2378,6 @@
 
        /* Wait for completion of async backlight requests */
        while (!bright_req_1.complete || !bright_req_2.complete ||
-
                        !batt_req.complete)
                pmu_poll();
 
@@ -3045,6 +3045,88 @@
 }
 #endif /* DEBUG_SLEEP */
 
+
+/* FIXME: This is a temporary set of callbacks to enable us
+ * to do suspend-to-disk.
+ */
+
+#ifdef CONFIG_PM
+
+static int pmu_sys_suspended = 0;
+
+static int pmu_sys_suspend(struct sys_device *sysdev, u32 state)
+{
+       if (state != PM_SUSPEND_DISK || pmu_sys_suspended)
+               return 0;
+
+       /* Suspend PMU event interrupts */
+       pmu_suspend();
+
+       pmu_sys_suspended = 1;
+       return 0;
+}
+
+static int pmu_sys_resume(struct sys_device *sysdev)
+{
+       struct adb_request req;
+
+       if (!pmu_sys_suspended)
+               return 0;
+
+       /* Tell PMU we are ready */
+       pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
+       pmu_wait_complete(&req);
+
+       /* Resume PMU event interrupts */
+       pmu_resume();
+
+       pmu_sys_suspended = 0;
+
+       return 0;
+}
+
+#endif /* CONFIG_PM */
+
+static struct sysdev_class pmu_sysclass = {
+       set_kset_name("pmu"),
+};
+
+static struct sys_device device_pmu = {
+       .id             = 0,
+       .cls            = &pmu_sysclass,
+};
+
+static struct sysdev_driver driver_pmu = {
+#ifdef CONFIG_PM
+       .suspend        = &pmu_sys_suspend,
+       .resume         = &pmu_sys_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init init_pmu_sysfs(void)
+{
+       int rc;
+
+       rc = sysdev_class_register(&pmu_sysclass);
+       if (rc) {
+               printk(KERN_ERR "Failed registering PMU sys class\n");
+               return -ENODEV;
+       }
+       rc = sysdev_register(&device_pmu);
+       if (rc) {
+               printk(KERN_ERR "Failed registering PMU sys device\n");
+               return -ENODEV;
+       }
+       rc = sysdev_driver_register(&pmu_sysclass, &driver_pmu);
+       if (rc) {
+               printk(KERN_ERR "Failed registering PMU sys driver\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+subsys_initcall(init_pmu_sysfs);
+
 EXPORT_SYMBOL(pmu_request);
 EXPORT_SYMBOL(pmu_poll);
 EXPORT_SYMBOL(pmu_poll_adb);
Index: drivers/ide/ppc/pmac.c
===================================================================
--- drivers/ide/ppc/pmac.c      (revision 26)
+++ drivers/ide/ppc/pmac.c      (working copy)
@@ -1372,7 +1372,7 @@
        ide_hwif_t      *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
        int             rc = 0;
 
-       if (state != mdev->ofdev.dev.power_state && state >= 2) {
+       if (state != mdev->ofdev.dev.power_state && state >= 2 && state != 4) {
                rc = pmac_ide_do_suspend(hwif);
                if (rc == 0)
                        mdev->ofdev.dev.power_state = state;
@@ -1480,7 +1480,7 @@
        ide_hwif_t      *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
        int             rc = 0;
        
-       if (state != pdev->dev.power_state && state >= 2) {
+       if (state != pdev->dev.power_state && state >= 2 && state != 4) {
                rc = pmac_ide_do_suspend(hwif);
                if (rc == 0)
                        pdev->dev.power_state = state;

Attachment: signature.asc
Description: Digital signature



Reply via email to