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 = ¤t->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;
signature.asc
Description: Digital signature