public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* SMP support for swsusp, and strange serio/i8042 problems
@ 2004-06-02 22:55 Pavel Machek
  2004-06-03  2:35 ` Dmitry Torokhov
  0 siblings, 1 reply; 2+ messages in thread
From: Pavel Machek @ 2004-06-02 22:55 UTC (permalink / raw)
  To: kernel list; +Cc: vojtech

Hi!

Here's experimental (works-for-me-mostly) SMP support for
swsusp. While debugging it, I hit strange problem with i8042
driver. If I change #if 0 to #if 1 *and* kernel is CONFIG_SMP, it dies
during first schedule(). Ouch.

Why is 8042 marked as system device, btw? Stopping timer for system
device is likely useless; first resume is called and only after that
interrupts are reenabled.

								Pavel

--- clean.amd/drivers/base/power/shutdown.c	2004-04-05 16:50:19.000000000 +0200
+++ linux/drivers/base/power/shutdown.c	2004-06-02 22:27:03.000000000 +0200
@@ -8,6 +8,7 @@
  *
  */
 
+#define DEBUG
 #include <linux/config.h>
 #include <linux/device.h>
 #include <asm/semaphore.h>
@@ -52,14 +53,14 @@
 	struct device * dev;
 	
 	down_write(&devices_subsys.rwsem);
+	printk("Shutting down devices: ");
 	list_for_each_entry_reverse(dev,&devices_subsys.kset.list,kobj.entry) {
-		pr_debug("shutting down %s: ",dev->bus_id);
 		if (dev->driver && dev->driver->shutdown) {
-			pr_debug("Ok\n");
+			printk("%s, ",dev->bus_id);
 			dev->driver->shutdown(dev);
-		} else
-			pr_debug("Ignored.\n");
+		}
 	}
+	printk("ok\n");
 	up_write(&devices_subsys.rwsem);
 
 	sysdev_shutdown();
--- clean.amd/drivers/base/power/suspend.c	2003-09-28 22:05:43.000000000 +0200
+++ linux/drivers/base/power/suspend.c	2004-06-02 22:38:56.000000000 +0200
@@ -113,10 +113,13 @@
 	int error = 0;
 	struct device * dev;
 
+	printk("Powering down devices: ");
 	list_for_each_entry_reverse(dev,&dpm_off_irq,power.entry) {
+		printk("%s ", dev->bus_id);
 		if ((error = suspend_device(dev,state)))
 			break;
 	} 
+	printk("ok?\n"); 
 	if (error)
 		goto Error;
 	if ((error = sysdev_suspend(state)))
--- clean.amd/drivers/base/sys.c	2004-04-05 16:50:19.000000000 +0200
+++ linux/drivers/base/sys.c	2004-06-02 23:13:07.000000000 +0200
@@ -302,18 +302,17 @@
 {
 	struct sysdev_class * cls;
 
-	pr_debug("Suspending System Devices\n");
+	printk("Suspending System Devices: ");
 
 	list_for_each_entry_reverse(cls,&system_subsys.kset.list,
 				    kset.kobj.entry) {
 		struct sys_device * sysdev;
 
-		pr_debug("Suspending type '%s':\n",
-			 kobject_name(&cls->kset.kobj));
+		printk("%s: ", kobject_name(&cls->kset.kobj));
 
 		list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
 			struct sysdev_driver * drv;
-			pr_debug(" %s\n",kobject_name(&sysdev->kobj));
+			printk(" %s, ",kobject_name(&sysdev->kobj));
 
 			/* Call global drivers first. */
 			list_for_each_entry(drv,&global_drivers,entry) {
@@ -332,6 +331,7 @@
 				cls->suspend(sysdev,state);
 		}
 	}
+	printk("ok\n");
 	return 0;
 }
 
@@ -349,17 +349,16 @@
 {
 	struct sysdev_class * cls;
 
-	pr_debug("Resuming System Devices\n");
+	printk("Resuming System Devices: ");
 
 	list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) {
 		struct sys_device * sysdev;
 
-		pr_debug("Resuming type '%s':\n",
-			 kobject_name(&cls->kset.kobj));
+		printk("%s: ", kobject_name(&cls->kset.kobj));
 
 		list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
 			struct sysdev_driver * drv;
-			pr_debug(" %s\n",kobject_name(&sysdev->kobj));
+			printk(" %s, ",kobject_name(&sysdev->kobj));
 
 			/* First, call the class-specific one */
 			if (cls->resume)
@@ -379,6 +378,7 @@
 
 		}
 	}
+	printk("ok\n");
 	return 0;
 }
 
--- clean.amd/drivers/input/serio/i8042.c	2004-04-05 16:50:21.000000000 +0200
+++ linux/drivers/input/serio/i8042.c	2004-06-02 23:32:15.000000000 +0200
@@ -832,12 +833,13 @@
 		return -1;
 	}
 
+#if 0
 	if (i8042_mux_present)
 		if (i8042_enable_mux_mode(&i8042_aux_values, NULL) ||
 		    i8042_enable_mux_ports(&i8042_aux_values)) {
 			printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't work.\n");
 		}
-
+#endif
 /*
  * Reconnect anything that was connected to the ports.
  */
@@ -845,12 +847,15 @@
 	if (i8042_kbd_values.exists && i8042_activate_port(&i8042_kbd_port) == 0)
 		serio_reconnect(&i8042_kbd_port);
 
+#if 0
 	if (i8042_aux_values.exists && i8042_activate_port(&i8042_aux_port) == 0)
 		serio_reconnect(&i8042_aux_port);
 
 	for (i = 0; i < 4; i++)
 		if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port + i) == 0)
 			serio_reconnect(i8042_mux_port + i);
+#endif
+
 /*
  * Restart timer (for polling "stuck" data)
  */
--- clean.amd/include/linux/suspend.h	2004-05-20 23:11:46.000000000 +0200
+++ linux/include/linux/suspend.h	2004-06-01 12:53:43.000000000 +0200
@@ -81,6 +81,14 @@
 }
 #endif	/* CONFIG_PM */
 
+#ifdef CONFIG_SMP
+extern void smp_freeze(void);
+extern void smp_restart(void);
+#else
+static inline void smp_freeze(void) {}
+static inline void smp_restart(void) {}
+#endif
+
 asmlinkage void do_magic(int is_resume);
 asmlinkage void do_magic_resume_1(void);
 asmlinkage void do_magic_resume_2(void);
--- clean.amd/kernel/power/Makefile	2003-09-28 22:06:44.000000000 +0200
+++ linux/kernel/power/Makefile	2004-06-01 12:53:43.000000000 +0200
@@ -1,4 +1,5 @@
 obj-y				:= main.o process.o console.o pm.o
+obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o
 obj-$(CONFIG_PM_DISK)		+= disk.o pmdisk.o
 
--- clean.amd/kernel/power/console.c	2004-02-20 12:39:39.000000000 +0100
+++ linux/kernel/power/console.c	2004-06-01 14:34:38.000000000 +0200
@@ -7,6 +7,7 @@
 #include <linux/vt_kern.h>
 #include <linux/kbd_kern.h>
 #include <linux/console.h>
+#include <linux/delay.h>
 #include "power.h"
 
 static int new_loglevel = 10;
--- clean.amd/kernel/power/smp.c	2004-05-21 11:49:20.000000000 +0200
+++ linux/kernel/power/smp.c	2004-06-03 00:22:43.000000000 +0200
@@ -1 +1,66 @@
+/*
+ * drivers/power/smp.c - Functions for stopping other CPUs.
+ *
+ * Copyright 2004 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2002-2003 Nigel Cunningham <ncunningham@clear.net.nz>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#undef DEBUG
+
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <asm/atomic.h>
+#include <asm/tlbflush.h>
+
+static atomic_t cpu_counter, freeze;
+
+static void smp_pause(void * data)
+{
+	atomic_inc(&cpu_counter);
+	while (atomic_read(&freeze)) {
+		cpu_relax();
+		barrier();
+	}
+	atomic_dec(&cpu_counter);
+	__flush_tlb_global();		/* CPU now wakes up into completely different system. Update its caches. */
+	/* Ahha, we might be expected to have different FPU registers etc. Ouch. */
+}
+
+void smp_freeze(void)
+{
+	printk("Freezing CPUs\n");
+	set_cpus_allowed(current, cpumask_of_cpu(0));
+	schedule();
+	printk("...");
+	BUG_ON(smp_processor_id() != 0);
+
+	/* FIXME: for this to work, all the CPUs must be running
+	 * "idle" thread (or we deadlock). Is that guaranteed? */
+
+	atomic_set(&cpu_counter, 0);
+	atomic_set(&freeze, 1);
+	smp_call_function(smp_pause, NULL, 0, 0);
+	while (atomic_read(&cpu_counter) < (num_online_cpus() - 1)) {
+		cpu_relax();
+		barrier();
+	}
+	printk("ok\n");
+}
+
+void smp_restart(void)
+{
+	printk("Restarting CPUs...");
+	atomic_set(&freeze, 0);
+	while (atomic_read(&cpu_counter)) {
+		cpu_relax();
+		barrier();
+	}
+	printk("ok\n");
+	/* FIXME: we probably should make this task go back to "any cpu" mode */
+}
+
 
--- clean.amd/kernel/power/swsusp.c	2004-05-21 12:26:43.000000000 +0200
+++ linux/kernel/power/swsusp.c	2004-06-02 23:46:56.000000000 +0200
@@ -851,8 +851,11 @@
 
 		free_some_memory();
 		
-		/* Save state of all device drivers, and stop them. */		   
-		if ((res = device_suspend(4))==0)
+		mdelay(1000);
+		smp_freeze();
+		/* Save state of all device drivers, and stop them. */
+		printk("Suspending devices... ");
+		if ((res = device_suspend(4))==0) {
 			/* If stopping device drivers worked, we proceed basically into
 			 * suspend_save_image.
 			 *
@@ -862,8 +865,16 @@
 			 * unsuspends all device drivers, and writes memory to disk
 			 * using normal kernel mechanism.
 			 */
+			printk("ok\n");
+#if 1
 			do_magic(0);
+#else
+			device_resume();
+#endif
+		}
 		thaw_processes();
+		printk("Processes thawed\n");
+		smp_restart();
 	} else
 		res = -EBUSY;
 	software_suspend_enabled = 1;
@@ -1187,8 +1198,7 @@
 static int __init software_resume(void)
 {
 	if (num_online_cpus() > 1) {
-		printk(KERN_WARNING "Software Suspend has malfunctioning SMP support. Disabled :(\n");	
-		return -EINVAL;
+		printk(KERN_WARNING "SMP support is very experimental.\n");	
 	}
 	/* We enable the possibility of machine suspend */
 	software_suspend_enabled = 1;
@@ -1215,6 +1225,8 @@
 	printk( "resuming from %s\n", resume_file);
 	if (read_suspend_image(resume_file, 0))
 		goto read_failure;
+	mdelay(1000);
+	smp_freeze();
 	device_suspend(4);
 	do_magic(1);
 	panic("This never returns");



-- 
934a471f20d6580d5aad759bf0d97ddc

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: SMP support for swsusp, and strange serio/i8042 problems
  2004-06-02 22:55 SMP support for swsusp, and strange serio/i8042 problems Pavel Machek
@ 2004-06-03  2:35 ` Dmitry Torokhov
  0 siblings, 0 replies; 2+ messages in thread
From: Dmitry Torokhov @ 2004-06-03  2:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: Pavel Machek, vojtech

On Wednesday 02 June 2004 05:55 pm, Pavel Machek wrote:
> Why is 8042 marked as system device, btw? 

What should it be? Seems to be a good classification for a KBC...

>                                           Stopping timer for system 
> device is likely useless; first resume is called and only after that
> interrupts are reenabled.
> 

The same routine is used for new and old (APM) style resume where running
timer may prevent system from suspending.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2004-06-03  2:35 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-06-02 22:55 SMP support for swsusp, and strange serio/i8042 problems Pavel Machek
2004-06-03  2:35 ` Dmitry Torokhov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox