swsusp updates

From: Pavel Machek (pavel@ucw.cz)
Date: Sat Jul 26 2003 - 15:45:28 EST


Hi!

This updates swsusp: CONFIG_SOFTWARE_SUSPEND and CONFIG_ACPI_SLEEP are
separated (it was getting users *badly* confused), remove too noisy
printk's, correctly restore console after S3, fixes suspend on
machines using yenta_socket.c, fixes some comments, cleans up
"interesting" macro mess in suspend.c, no longer eats filesystems when
process is ^Z-ed before suspend. Please apply,

                                                                Pavel

Index: linux/drivers/acpi/sleep/main.c
===================================================================
--- linux.orig/drivers/acpi/sleep/main.c 2003-07-22 13:39:42.000000000 +0200
+++ linux/drivers/acpi/sleep/main.c 2003-07-22 12:53:27.000000000 +0200
@@ -69,10 +81,6 @@
  * First, we call to the device driver layer to save device state.
  * Once we have that, we save whatevery processor and kernel state we
  * need to memory.
- * If we're entering S4, we then write the memory image to disk.
- *
- * Only then is it safe for us to power down devices, since we may need
- * the disks and upstream buses to write to.
  */
 acpi_status
 acpi_system_save_state(
@@ -197,7 +205,7 @@
                 break;
         }
         local_irq_restore(flags);
- printk(KERN_CRIT "Back to C!\n");
+ printk(KERN_DEBUG "Back to C!\n");
 
         return status;
 }
@@ -226,6 +234,7 @@
         if (state == ACPI_STATE_S4 && !acpi_gbl_FACS->S4bios_f)
                 return AE_ERROR;
 
+ prepare_suspend_console();
         /*
          * TBD: S1 can be done without device_suspend. Make a CONFIG_XX
          * to handle however when S1 failed without device_suspend.
@@ -270,6 +279,7 @@
         /* reset firmware waking vector */
         acpi_set_firmware_waking_vector((acpi_physical_address) 0);
         thaw_processes();
+ restore_console();
 
         return status;
 }
Index: linux/arch/i386/kernel/Makefile
===================================================================
--- linux.orig/arch/i386/kernel/Makefile 2003-07-22 13:39:42.000000000 +0200
+++ linux/arch/i386/kernel/Makefile 2003-07-17 22:22:58.000000000 +0200
@@ -24,7 +24,8 @@
 obj-$(CONFIG_X86_MPPARSE) += mpparse.o
 obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
 obj-$(CONFIG_X86_IO_APIC) += io_apic.o
-obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o suspend_asm.o
+obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
+obj-$(CONFIG_PM) += suspend_asm.o
 obj-$(CONFIG_X86_NUMAQ) += numaq.o
 obj-$(CONFIG_X86_SUMMIT) += summit.o
 obj-$(CONFIG_EDD) += edd.o
Index: linux/arch/i386/kernel/suspend_asm.S
===================================================================
--- linux.orig/arch/i386/kernel/suspend_asm.S 2003-07-22 13:39:42.000000000 +0200
+++ linux/arch/i386/kernel/suspend_asm.S 2003-07-20 15:02:12.000000000 +0200
@@ -32,6 +32,7 @@
 saved_context_eflags:
         .long 0
 
+#ifdef CONFIG_SOFTWARE_SUSPEND
         .text
 
 ENTRY(do_magic)
@@ -117,4 +118,4 @@
 loop2:
        .quad 0
        .previous
-
\ No newline at end of file
+#endif
Index: linux/arch/i386/kernel/sysenter.c
===================================================================
--- linux.orig/arch/i386/kernel/sysenter.c 2003-07-22 13:39:42.000000000 +0200
+++ linux/arch/i386/kernel/sysenter.c 2003-07-17 22:22:58.000000000 +0200
@@ -31,8 +31,6 @@
         wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
         wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0);
         wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0);
-
- printk("Enabling SEP on CPU %d\n", cpu);
         put_cpu();
 }
 
Index: linux/drivers/acpi/Kconfig
===================================================================
--- linux.orig/drivers/acpi/Kconfig 2003-07-22 13:39:42.000000000 +0200
+++ linux/drivers/acpi/Kconfig 2003-07-17 22:22:58.000000000 +0200
@@ -58,8 +58,8 @@
         default y
 
 config ACPI_SLEEP
- bool "Sleep States"
- depends on X86 && ACPI && !ACPI_HT_ONLY && SOFTWARE_SUSPEND
+ bool "Sleep States (EXPERIMENTAL)"
+ depends on X86 && ACPI && !ACPI_HT_ONLY && EXPERIMENTAL
         ---help---
           This option adds support for ACPI suspend states.
 
Index: linux/drivers/base/power.c
===================================================================
--- linux.orig/drivers/base/power.c 2003-07-22 13:39:42.000000000 +0200
+++ linux/drivers/base/power.c 2003-07-17 22:22:58.000000000 +0200
@@ -52,8 +52,6 @@
         struct device * dev;
         int error = 0;
 
- printk(KERN_EMERG "Suspending devices\n");
-
         down_write(&devices_subsys.rwsem);
         list_for_each_entry_reverse(dev,&devices_subsys.kset.list,kobj.entry) {
                 if (dev->driver && dev->driver->suspend) {
@@ -114,8 +112,6 @@
                 }
         }
         up_write(&devices_subsys.rwsem);
-
- printk(KERN_EMERG "Devices Resumed\n");
 }
 
 /**
@@ -125,8 +121,6 @@
 {
         struct device * dev;
         
- printk(KERN_EMERG "Shutting down devices\n");
-
         down_write(&devices_subsys.rwsem);
         list_for_each_entry_reverse(dev,&devices_subsys.kset.list,kobj.entry) {
                 pr_debug("shutting down %s: ",dev->name);
Index: linux/drivers/pcmcia/yenta_socket.c
===================================================================
--- linux.orig/drivers/pcmcia/yenta_socket.c 2003-07-22 13:39:42.000000000 +0200
+++ linux/drivers/pcmcia/yenta_socket.c 2003-07-17 22:22:58.000000000 +0200
@@ -899,7 +899,10 @@
 
 static int yenta_dev_suspend (struct pci_dev *dev, u32 state)
 {
- return pcmcia_socket_dev_suspend(&dev->dev, state, 0);
+ /* FIXME: We should really let devices to act on *all* levels :-(.
+ If you put something else than SUSPEND_SAVE_STATE,
+ pcmcia_socket_dev_suspend() will simply do nothing due to its check. */
+ return pcmcia_socket_dev_suspend(&dev->dev, state, SUSPEND_SAVE_STATE);
 }
 
 
Index: linux/include/linux/reboot.h
===================================================================
--- linux.orig/include/linux/reboot.h 2003-07-22 13:39:42.000000000 +0200
+++ linux/include/linux/reboot.h 2003-07-17 22:22:58.000000000 +0200
@@ -21,7 +21,7 @@
  * CAD_OFF Ctrl-Alt-Del sequence sends SIGINT to init task.
  * POWER_OFF Stop OS and remove all power from system, if possible.
  * RESTART2 Restart system using given command string.
- * SW_SUSPEND Suspend system using Software Suspend if compiled in
+ * SW_SUSPEND Suspend system using software suspend if compiled in.
  */
 
 #define LINUX_REBOOT_CMD_RESTART 0x01234567
Index: linux/include/linux/suspend.h
===================================================================
--- linux.orig/include/linux/suspend.h 2003-07-22 13:39:42.000000000 +0200
+++ linux/include/linux/suspend.h 2003-07-22 12:54:08.000000000 +0200
@@ -55,10 +55,6 @@
 
 extern int register_suspend_notifier(struct notifier_block *);
 extern int unregister_suspend_notifier(struct notifier_block *);
-extern void refrigerator(unsigned long);
-
-extern int freeze_processes(void);
-extern void thaw_processes(void);
 
 extern unsigned int nr_copy_pages __nosavedata;
 extern suspend_pagedir_t *pagedir_nosave __nosavedata;
@@ -76,15 +72,23 @@
 extern void do_suspend_lowlevel_s4bios(int resume);
 
 #else
-static inline void software_suspend(void)
-{
-}
+static inline void software_suspend(void) { }
 #define software_resume() do { } while(0)
 #define register_suspend_notifier(a) do { } while(0)
 #define unregister_suspend_notifier(a) do { } while(0)
+#endif
+
+#ifdef CONFIG_PM
+extern void refrigerator(unsigned long);
+extern int freeze_processes(void);
+extern void thaw_processes(void);
+#else
 #define refrigerator(a) do { BUG(); } while(0)
 #define freeze_processes() do { panic("You need CONFIG_SOFTWARE_SUSPEND to do sleeps."); } while(0)
 #define thaw_processes() do { } while(0)
 #endif
 
+extern int prepare_suspend_console(void);
+extern void restore_console(void);
+
 #endif /* _LINUX_SWSUSP_H */
Index: linux/kernel/Makefile
===================================================================
--- linux.orig/kernel/Makefile 2003-07-22 13:39:43.000000000 +0200
+++ linux/kernel/Makefile 2003-07-17 22:22:58.000000000 +0200
@@ -17,7 +17,7 @@
 obj-$(CONFIG_PM) += pm.o
 obj-$(CONFIG_CPU_FREQ) += cpufreq.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
-obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
+obj-$(CONFIG_PM) += suspend.o
 obj-$(CONFIG_COMPAT) += compat.o
 
 ifneq ($(CONFIG_IA64),y)
Index: linux/kernel/suspend.c
===================================================================
--- linux.orig/kernel/suspend.c 2003-07-22 13:39:43.000000000 +0200
+++ linux/kernel/suspend.c 2003-07-22 13:46:26.000000000 +0200
@@ -5,7 +5,7 @@
  * machine suspend feature using pretty near only high-level routines
  *
  * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
- * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 1998,2001-2003 Pavel Machek <pavel@suse.cz>
  *
  * I'd like to thank the following people for their work:
  *
@@ -65,6 +65,7 @@
 #include <asm/pgtable.h>
 #include <asm/io.h>
 
+#ifdef CONFIG_SOFTWARE_SUSPEND
 extern long sys_sync(void);
 
 unsigned char software_suspend_enabled = 0;
@@ -78,7 +79,6 @@
 #undef SUSPEND_CONSOLE
 #endif
 
-#define TIMEOUT (6 * HZ) /* Timeout for stopping processes */
 #define __ADDRESS(x) ((unsigned long) phys_to_virt(x))
 #define ADDRESS(x) __ADDRESS((x) << PAGE_SHIFT)
 #define ADDRESS2(x) __ADDRESS(__pa(x)) /* Needed for x86-64 where some pages are in memory twice */
@@ -139,39 +139,45 @@
 
 static const char name_suspend[] = "Suspend Machine: ";
 static const char name_resume[] = "Resume Machine: ";
+#endif
 
 /*
  * Debug
  */
-#define DEBUG_DEFAULT
-#undef DEBUG_PROCESS
+#undef DEBUG_DEFAULT
 #undef DEBUG_SLOW
-#define TEST_SWSUSP 0 /* Set to 1 to reboot instead of halt machine after suspension */
+#define TEST_SWSUSP 0 /* Set to 1 to reboot instead of halt machine after suspension */
 
 #ifdef DEBUG_DEFAULT
-# define PRINTK(f, a...) printk(f, ## a)
+# define PRINTK(f, a...) printk(f, ## a)
 #else
-# define PRINTK(f, a...)
+# define PRINTK(f, a...) do {} while (0)
 #endif
 
 #ifdef DEBUG_SLOW
 #define MDELAY(a) mdelay(a)
 #else
-#define MDELAY(a)
+#define MDELAY(a) do {} while (0)
 #endif
 
 /*
  * Refrigerator and related stuff
  */
 
-#define INTERESTING(p) \
- /* We don't want to touch kernel_threads..*/ \
- if (p->flags & PF_IOTHREAD) \
- continue; \
- if (p == current) \
- continue; \
- if (p->state == TASK_ZOMBIE) \
- continue;
+/* 0 = Ignore this process when freezing/thawing, 1 = freeze/thaw this process */
+static inline int interesting_process(struct task_struct *p)
+{
+ if (p->flags & PF_IOTHREAD)
+ return 0;
+ if (p == current)
+ return 0;
+ if ((p->state == TASK_ZOMBIE) || (p->state == TASK_DEAD))
+ return 0;
+
+ return 1;
+}
+
+#define TIMEOUT (6 * HZ) /* Timeout for stopping processes */
 
 /* Refrigerator is place where frozen processes are stored :-). */
 void refrigerator(unsigned long flag)
@@ -212,9 +218,12 @@
                 read_lock(&tasklist_lock);
                 do_each_thread(g, p) {
                         unsigned long flags;
- INTERESTING(p);
+ if (!interesting_process(p))
+ continue;
                         if (p->flags & PF_FROZEN)
                                 continue;
+ if (p->state == TASK_STOPPED)
+ continue;
 
                         /* FIXME: smp problem here: we may not access other process' flags
                            without locking */
@@ -245,19 +254,56 @@
         printk( "Restarting tasks..." );
         read_lock(&tasklist_lock);
         do_each_thread(g, p) {
- INTERESTING(p);
-
- if (p->flags & PF_FROZEN) p->flags &= ~PF_FROZEN;
- else
- printk(KERN_INFO " Strange, %s not stopped\n", p->comm );
- wake_up_process(p);
+ if (!interesting_process(p))
+ continue;
+ if (p->flags & PF_FROZEN) {
+ p->flags &= ~PF_FROZEN;
+ wake_up_process(p);
+ } else
+ PRINTK(KERN_INFO " Strange, %s not frozen\n", p->comm );
         } while_each_thread(g, p);
 
         read_unlock(&tasklist_lock);
+ schedule();
         printk( " done\n" );
         MDELAY(500);
 }
 
+int prepare_suspend_console(void)
+{
+ orig_loglevel = console_loglevel;
+ console_loglevel = new_loglevel;
+
+#ifdef CONFIG_VT
+ orig_fgconsole = fg_console;
+#ifdef SUSPEND_CONSOLE
+ if(vc_allocate(SUSPEND_CONSOLE))
+ /* we can't have a free VC for now. Too bad,
+ * we don't want to mess the screen for now. */
+ return 1;
+
+ set_console (SUSPEND_CONSOLE);
+ if (vt_waitactive(SUSPEND_CONSOLE)) {
+ printk(KERN_ERR "Bummer. Can't switch VCs.\n");
+ return 1;
+ }
+ orig_kmsg = kmsg_redirect;
+ kmsg_redirect = SUSPEND_CONSOLE;
+#endif
+#endif
+ return 0;
+}
+
+void restore_console(void)
+{
+ console_loglevel = orig_loglevel;
+#ifdef SUSPEND_CONSOLE
+ set_console (orig_fgconsole);
+#endif
+ return;
+}
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
 /*
  * Saving part...
  */
@@ -283,17 +329,6 @@
         return 0;
 }
 
-/*
- * This is our sync function. With this solution we probably won't sleep
- * but that should not be a problem since tasks are stopped..
- */
-
-static inline void do_suspend_sync(void)
-{
- blk_run_queues();
-#warning This might be broken. We need to somehow wait for data to reach the disk
-}
-
 /* We memorize in swapfile_used what swap devices are used for suspension */
 #define SWAPFILE_UNUSED 0
 #define SWAPFILE_SUSPEND 1 /* This is the suspending device */
@@ -561,7 +596,6 @@
                         free_suspend_pagedir((unsigned long) pagedir);
                         return NULL;
                 }
- printk(".");
                 SetPageNosave(virt_to_page(p->address));
                 p->orig_address = 0;
                 p++;
@@ -569,39 +603,6 @@
         return pagedir;
 }
 
-static int prepare_suspend_console(void)
-{
- orig_loglevel = console_loglevel;
- console_loglevel = new_loglevel;
-
-#ifdef CONFIG_VT
- orig_fgconsole = fg_console;
-#ifdef SUSPEND_CONSOLE
- if(vc_allocate(SUSPEND_CONSOLE))
- /* we can't have a free VC for now. Too bad,
- * we don't want to mess the screen for now. */
- return 1;
-
- set_console (SUSPEND_CONSOLE);
- if(vt_waitactive(SUSPEND_CONSOLE)) {
- PRINTK("Bummer. Can't switch VCs.");
- return 1;
- }
- orig_kmsg = kmsg_redirect;
- kmsg_redirect = SUSPEND_CONSOLE;
-#endif
-#endif
- return 0;
-}
-
-static void restore_console(void)
-{
- console_loglevel = orig_loglevel;
-#ifdef SUSPEND_CONSOLE
- set_console (orig_fgconsole);
-#endif
- return;
-}
 
 static int prepare_suspend_processes(void)
 {
@@ -852,7 +853,6 @@
         free_pages((unsigned long) pagedir_nosave, pagedir_order);
         spin_unlock_irq(&suspend_pagedir_lock);
         mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
- PRINTK(KERN_WARNING "%sLeaving do_magic_suspend_2...\n", name_suspend);
 }
 
 static void do_software_suspend(void)
@@ -861,20 +861,13 @@
         if (prepare_suspend_console())
                 printk( "%sCan't allocate a console... proceeding\n", name_suspend);
         if (!prepare_suspend_processes()) {
-
                 /* At this point, all user processes and "dangerous"
                    kernel threads are stopped. Free some memory, as we
                    need half of memory free. */
-
                 free_some_memory();
                 
- /* No need to invalidate any vfsmnt list -- they will be valid after resume, anyway.
- *
- * We sync here -- so you have consistent filesystem state when things go wrong.
- * -- so that noone writes to disk after we do atomic copy of data.
- */
- PRINTK("Syncing disks before copy\n");
- do_suspend_sync();
+ /* No need to invalidate any vfsmnt list -- they will be valid after resume, anyway. */
+ blk_run_queues();
 
                 /* Save state of all device drivers, and stop them. */
                 if(drivers_suspend()==0)
@@ -888,12 +881,11 @@
                          * using normal kernel mechanism.
                          */
                         do_magic(0);
- PRINTK("Restarting processes...\n");
                 thaw_processes();
         }
         software_suspend_enabled = 1;
         MDELAY(1000);
- restore_console ();
+ restore_console();
 }
 
 /*
@@ -906,7 +898,7 @@
                 return;
 
         software_suspend_enabled = 0;
- BUG_ON(in_interrupt());
+ BUG_ON(in_atomic());
         do_software_suspend();
 }
 
@@ -1279,4 +1271,5 @@
 
 EXPORT_SYMBOL(software_suspend);
 EXPORT_SYMBOL(software_suspend_enabled);
+#endif
 EXPORT_SYMBOL(refrigerator);
Index: linux/arch/i386/kernel/acpi/wakeup.S
===================================================================
--- linux.orig/arch/i386/kernel/acpi/wakeup.S 2003-07-22 13:39:42.000000000 +0200
+++ linux/arch/i386/kernel/acpi/wakeup.S 2003-07-22 13:26:01.000000000 +0200
@@ -43,6 +43,11 @@
 
         testl $1, video_flags - wakeup_code
         jz 1f
+ /* It is miracle that this works:
+ * PCI may or may not be initialized at this point
+ * I'm told we should pass device ID to video bios
+ However it works on some real machines...
+ */
         lcall $0xc000,$3
         movw %cs, %ax
         movw %ax, %ds # Bios might have played with that

-- 
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Jul 31 2003 - 22:00:30 EST