public inbox for linux-acpi@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] Patches for 2.6.27
@ 2008-05-06 21:31 Rafael J. Wysocki
  2008-05-06 21:33 ` [PATCH 1/4] ACPI Hibernation: Use ACPI hardware signature Rafael J. Wysocki
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Rafael J. Wysocki @ 2008-05-06 21:31 UTC (permalink / raw)
  To: Len Brown
  Cc: ACPI Devel Maling List, pm list, Pavel Machek, Johannes Berg,
	Shaohua Li, David Brownell, Jesse Barnes

Hi Len,

The following patches are for inclusion in the 2.6.27 patch queue.  They apply
on top of the latest -git, AFAICS.

Thanks,
Rafael


-- 
"Premature optimization is the root of all evil." - Donald Knuth


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

* [PATCH 1/4] ACPI Hibernation: Use ACPI hardware signature
  2008-05-06 21:31 [PATCH 0/4] Patches for 2.6.27 Rafael J. Wysocki
@ 2008-05-06 21:33 ` Rafael J. Wysocki
  2008-05-07  9:20   ` Pavel Machek
  2008-05-06 21:35 ` [PATCH 2/4] APM emulation: Notify about all suspend events, not just APM invoked ones (v2) Rafael J. Wysocki
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Rafael J. Wysocki @ 2008-05-06 21:33 UTC (permalink / raw)
  To: Len Brown
  Cc: ACPI Devel Maling List, pm list, Pavel Machek, Johannes Berg,
	Shaohua Li, David Brownell, Jesse Barnes

From: Shaohua Li <shaohua.li@intel.com>

ACPI defines a hardware signature. BIOS calculates the signature
according to hardware configure, if hardware changes, the signature
will change, in this case, S4 resume should fail.

Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/acpi/sleep/main.c |   24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

Index: linux-2.6/drivers/acpi/sleep/main.c
===================================================================
--- linux-2.6.orig/drivers/acpi/sleep/main.c
+++ linux-2.6/drivers/acpi/sleep/main.c
@@ -255,6 +255,17 @@ static struct dmi_system_id __initdata a
 #endif /* CONFIG_SUSPEND */
 
 #ifdef CONFIG_HIBERNATION
+static unsigned long s4_hardware_signature;
+static struct acpi_table_facs *facs;
+static bool nosigcheck;
+
+static int __init acpi_s4_nosigcheck(char *str)
+{
+	nosigcheck = true;
+	return 1;
+}
+__setup("acpi_s4_nosigcheck", acpi_s4_nosigcheck);
+
 static int acpi_hibernation_begin(void)
 {
 	acpi_target_sleep_state = ACPI_STATE_S4;
@@ -301,6 +312,12 @@ static void acpi_hibernation_leave(void)
 	acpi_enable();
 	/* Reprogram control registers and execute _BFS */
 	acpi_leave_sleep_state_prep(ACPI_STATE_S4);
+	/* Check the hardware signature */
+	if (facs && s4_hardware_signature != facs->hardware_signature) {
+		printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
+			"cannot resume!\n");
+		panic("ACPI S4 hardware signature mismatch");
+	}
 }
 
 static void acpi_hibernation_finish(void)
@@ -501,6 +518,13 @@ int __init acpi_sleep_init(void)
 		hibernation_set_ops(&acpi_hibernation_ops);
 		sleep_states[ACPI_STATE_S4] = 1;
 		printk(" S4");
+		if (!nosigcheck) {
+			acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+				(struct acpi_table_header **)&facs);
+			if (facs)
+				s4_hardware_signature =
+					facs->hardware_signature;
+		}
 	}
 #endif
 	status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);

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

* [PATCH 2/4] APM emulation: Notify about all suspend events, not just APM invoked ones (v2)
  2008-05-06 21:31 [PATCH 0/4] Patches for 2.6.27 Rafael J. Wysocki
  2008-05-06 21:33 ` [PATCH 1/4] ACPI Hibernation: Use ACPI hardware signature Rafael J. Wysocki
@ 2008-05-06 21:35 ` Rafael J. Wysocki
  2008-05-07  9:22   ` Pavel Machek
  2008-05-06 21:37 ` [PATCH 3/4] ACPI PM: acpi_pm_device_sleep_state() cleanup Rafael J. Wysocki
  2008-05-06 21:38 ` [PATCH 4/4] PCI ACPI: Drop the second argument of platform_pci_choose_state Rafael J. Wysocki
  3 siblings, 1 reply; 11+ messages in thread
From: Rafael J. Wysocki @ 2008-05-06 21:35 UTC (permalink / raw)
  To: Len Brown
  Cc: ACPI Devel Maling List, pm list, Pavel Machek, Johannes Berg,
	Shaohua Li, David Brownell, Jesse Barnes

From: Johannes Berg <johannes@sipsolutions.net>

This revamps the apm-emulation code to get suspend notifications
regardless of what way pm_suspend() was invoked, whether via the
apm ioctl or via /sys/power/state. Also do some code cleanup and
add comments while at it.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---

 drivers/char/apm-emulation.c |  346 +++++++++++++++++++++++++------------------
 1 file changed, 207 insertions(+), 139 deletions(-)

Index: linux-2.6/drivers/char/apm-emulation.c
===================================================================
--- linux-2.6.orig/drivers/char/apm-emulation.c
+++ linux-2.6/drivers/char/apm-emulation.c
@@ -58,6 +58,55 @@ struct apm_queue {
 };
 
 /*
+ * thread states (for threads using a writable /dev/apm_bios fd):
+ *
+ * SUSPEND_NONE:	nothing happening
+ * SUSPEND_PENDING:	suspend event queued for thread and pending to be read
+ * SUSPEND_READ:	suspend event read, pending acknowledgement
+ * SUSPEND_ACKED:	acknowledgement received from thread (via ioctl),
+ *			waiting for resume
+ * SUSPEND_ACKTO:	acknowledgement timeout
+ * SUSPEND_DONE:	thread had acked suspend and is now notified of
+ *			resume
+ *
+ * SUSPEND_WAIT:	this thread invoked suspend and is waiting for resume
+ *
+ * A thread migrates in one of three paths:
+ * 	NONE -1-> PENDING -2-> READ -3-> ACKED -4-> DONE -5-> NONE
+ *	                            -6-> ACKTO -7-> NONE
+ *	NONE -8-> WAIT -9-> NONE
+ *
+ * While in PENDING or READ, the thread is accounted for in the
+ * suspend_acks_pending counter.
+ *
+ * The transitions are invoked as follows:
+ *	1: suspend event is signalled from the core PM code
+ *	2: the suspend event is read from the fd by the userspace thread
+ *	3: userspace thread issues the APM_IOC_SUSPEND ioctl (as ack)
+ *	4: core PM code signals that we have resumed
+ *	5: APM_IOC_SUSPEND ioctl returns
+ *
+ *	6: the notifier invoked from the core PM code timed out waiting
+ *	   for all relevant threds to enter ACKED state and puts those
+ *	   that haven't into ACKTO
+ *	7: those threads issue APM_IOC_SUSPEND ioctl too late,
+ *	   get an error
+ *
+ *	8: userspace thread issues the APM_IOC_SUSPEND ioctl (to suspend),
+ *	   ioctl code invokes pm_suspend()
+ *	9: pm_suspend() returns indicating resume
+ */
+enum apm_suspend_state {
+	SUSPEND_NONE,
+	SUSPEND_PENDING,
+	SUSPEND_READ,
+	SUSPEND_ACKED,
+	SUSPEND_ACKTO,
+	SUSPEND_WAIT,
+	SUSPEND_DONE,
+};
+
+/*
  * The per-file APM data
  */
 struct apm_user {
@@ -68,13 +117,7 @@ struct apm_user {
 	unsigned int		reader: 1;
 
 	int			suspend_result;
-	unsigned int		suspend_state;
-#define SUSPEND_NONE	0		/* no suspend pending */
-#define SUSPEND_PENDING	1		/* suspend pending read */
-#define SUSPEND_READ	2		/* suspend read, pending ack */
-#define SUSPEND_ACKED	3		/* suspend acked */
-#define SUSPEND_WAIT	4		/* waiting for suspend */
-#define SUSPEND_DONE	5		/* suspend completed */
+	enum apm_suspend_state	suspend_state;
 
 	struct apm_queue	queue;
 };
@@ -82,7 +125,8 @@ struct apm_user {
 /*
  * Local variables
  */
-static int suspends_pending;
+static atomic_t suspend_acks_pending = ATOMIC_INIT(0);
+static atomic_t userspace_notification_inhibit = ATOMIC_INIT(0);
 static int apm_disabled;
 static struct task_struct *kapmd_tsk;
 
@@ -165,78 +209,6 @@ static void queue_event(apm_event_t even
 	wake_up_interruptible(&apm_waitqueue);
 }
 
-/*
- * queue_suspend_event - queue an APM suspend event.
- *
- * Check that we're in a state where we can suspend.  If not,
- * return -EBUSY.  Otherwise, queue an event to all "writer"
- * users.  If there are no "writer" users, return '1' to
- * indicate that we can immediately suspend.
- */
-static int queue_suspend_event(apm_event_t event, struct apm_user *sender)
-{
-	struct apm_user *as;
-	int ret = 1;
-
-	mutex_lock(&state_lock);
-	down_read(&user_list_lock);
-
-	/*
-	 * If a thread is still processing, we can't suspend, so reject
-	 * the request.
-	 */
-	list_for_each_entry(as, &apm_user_list, list) {
-		if (as != sender && as->reader && as->writer && as->suser &&
-		    as->suspend_state != SUSPEND_NONE) {
-			ret = -EBUSY;
-			goto out;
-		}
-	}
-
-	list_for_each_entry(as, &apm_user_list, list) {
-		if (as != sender && as->reader && as->writer && as->suser) {
-			as->suspend_state = SUSPEND_PENDING;
-			suspends_pending++;
-			queue_add_event(&as->queue, event);
-			ret = 0;
-		}
-	}
- out:
-	up_read(&user_list_lock);
-	mutex_unlock(&state_lock);
-	wake_up_interruptible(&apm_waitqueue);
-	return ret;
-}
-
-static void apm_suspend(void)
-{
-	struct apm_user *as;
-	int err = pm_suspend(PM_SUSPEND_MEM);
-
-	/*
-	 * Anyone on the APM queues will think we're still suspended.
-	 * Send a message so everyone knows we're now awake again.
-	 */
-	queue_event(APM_NORMAL_RESUME);
-
-	/*
-	 * Finally, wake up anyone who is sleeping on the suspend.
-	 */
-	mutex_lock(&state_lock);
-	down_read(&user_list_lock);
-	list_for_each_entry(as, &apm_user_list, list) {
-		if (as->suspend_state == SUSPEND_WAIT ||
-		    as->suspend_state == SUSPEND_ACKED) {
-			as->suspend_result = err;
-			as->suspend_state = SUSPEND_DONE;
-		}
-	}
-	up_read(&user_list_lock);
-	mutex_unlock(&state_lock);
-
-	wake_up(&apm_suspend_waitqueue);
-}
-
 static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
 {
 	struct apm_user *as = fp->private_data;
@@ -307,25 +279,22 @@ apm_ioctl(struct inode * inode, struct f
 
 		as->suspend_result = -EINTR;
 
-		if (as->suspend_state == SUSPEND_READ) {
-			int pending;
-
+		switch (as->suspend_state) {
+		case SUSPEND_READ:
 			/*
 			 * If we read a suspend command from /dev/apm_bios,
 			 * then the corresponding APM_IOC_SUSPEND ioctl is
 			 * interpreted as an acknowledge.
 			 */
 			as->suspend_state = SUSPEND_ACKED;
-			suspends_pending--;
-			pending = suspends_pending == 0;
+			atomic_dec(&suspend_acks_pending);
 			mutex_unlock(&state_lock);
 
 			/*
-			 * If there are no further acknowledges required,
-			 * suspend the system.
+			 * suspend_acks_pending changed, the notifier needs to
+			 * be woken up for this
 			 */
-			if (pending)
-				apm_suspend();
+			wake_up(&apm_suspend_waitqueue);
 
 			/*
 			 * Wait for the suspend/resume to complete.  If there
@@ -341,35 +310,21 @@ apm_ioctl(struct inode * inode, struct f
 			 * try_to_freeze() in freezer_count() will not trigger
 			 */
 			freezer_count();
-		} else {
+			break;
+		case SUSPEND_ACKTO:
+			as->suspend_result = -ETIMEDOUT;
+			mutex_unlock(&state_lock);
+			break;
+		default:
 			as->suspend_state = SUSPEND_WAIT;
 			mutex_unlock(&state_lock);
 
 			/*
 			 * Otherwise it is a request to suspend the system.
-			 * Queue an event for all readers, and expect an
-			 * acknowledge from all writers who haven't already
-			 * acknowledged.
-			 */
-			err = queue_suspend_event(APM_USER_SUSPEND, as);
-			if (err < 0) {
-				/*
-				 * Avoid taking the lock here - this
-				 * should be fine.
-				 */
-				as->suspend_state = SUSPEND_NONE;
-				break;
-			}
-
-			if (err > 0)
-				apm_suspend();
-
-			/*
-			 * Wait for the suspend/resume to complete.  If there
-			 * are pending acknowledges, we wait here for them.
+			 * Just invoke pm_suspend(), we'll handle it from
+			 * there via the notifier.
 			 */
-			wait_event_freezable(apm_suspend_waitqueue,
-					 as->suspend_state == SUSPEND_DONE);
+			as->suspend_result = pm_suspend(PM_SUSPEND_MEM);
 		}
 
 		mutex_lock(&state_lock);
@@ -385,7 +340,6 @@ apm_ioctl(struct inode * inode, struct f
 static int apm_release(struct inode * inode, struct file * filp)
 {
 	struct apm_user *as = filp->private_data;
-	int pending = 0;
 
 	filp->private_data = NULL;
 
@@ -395,18 +349,15 @@ static int apm_release(struct inode * in
 
 	/*
 	 * We are now unhooked from the chain.  As far as new
-	 * events are concerned, we no longer exist.  However, we
-	 * need to balance suspends_pending, which means the
-	 * possibility of sleeping.
+	 * events are concerned, we no longer exist.
 	 */
 	mutex_lock(&state_lock);
-	if (as->suspend_state != SUSPEND_NONE) {
-		suspends_pending -= 1;
-		pending = suspends_pending == 0;
-	}
+	if (as->suspend_state == SUSPEND_PENDING ||
+	    as->suspend_state == SUSPEND_READ)
+		atomic_dec(&suspend_acks_pending);
 	mutex_unlock(&state_lock);
-	if (pending)
-		apm_suspend();
+
+	wake_up(&apm_suspend_waitqueue);
 
 	kfree(as);
 	return 0;
@@ -542,7 +493,6 @@ static int kapmd(void *arg)
 {
 	do {
 		apm_event_t event;
-		int ret;
 
 		wait_event_interruptible(kapmd_wait,
 				!queue_empty(&kapmd_queue) || kthread_should_stop());
@@ -567,20 +517,13 @@ static int kapmd(void *arg)
 
 		case APM_USER_SUSPEND:
 		case APM_SYS_SUSPEND:
-			ret = queue_suspend_event(event, NULL);
-			if (ret < 0) {
-				/*
-				 * We were busy.  Try again in 50ms.
-				 */
-				queue_add_event(&kapmd_queue, event);
-				msleep(50);
-			}
-			if (ret > 0)
-				apm_suspend();
+			pm_suspend(PM_SUSPEND_MEM);
 			break;
 
 		case APM_CRITICAL_SUSPEND:
-			apm_suspend();
+			atomic_inc(&userspace_notification_inhibit);
+			pm_suspend(PM_SUSPEND_MEM);
+			atomic_dec(&userspace_notification_inhibit);
 			break;
 		}
 	} while (1);
@@ -588,6 +531,120 @@ static int kapmd(void *arg)
 	return 0;
 }
 
+static int apm_suspend_notifier(struct notifier_block *nb,
+				unsigned long event,
+				void *dummy)
+{
+	struct apm_user *as;
+	int err;
+
+	/* short-cut emergency suspends */
+	if (atomic_read(&userspace_notification_inhibit))
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		/*
+		 * Queue an event to all "writer" users that we want
+		 * to suspend and need their ack.
+		 */
+		mutex_lock(&state_lock);
+		down_read(&user_list_lock);
+
+		list_for_each_entry(as, &apm_user_list, list) {
+			if (as->suspend_state != SUSPEND_WAIT && as->reader &&
+			    as->writer && as->suser) {
+				as->suspend_state = SUSPEND_PENDING;
+				atomic_inc(&suspend_acks_pending);
+				queue_add_event(&as->queue, APM_USER_SUSPEND);
+			}
+		}
+
+		up_read(&user_list_lock);
+		mutex_unlock(&state_lock);
+		wake_up_interruptible(&apm_waitqueue);
+
+		/*
+		 * Wait for the the suspend_acks_pending variable to drop to
+		 * zero, meaning everybody acked the suspend event (or the
+		 * process was killed.)
+		 *
+		 * If the app won't answer within a short while we assume it
+		 * locked up and ignore it.
+		 */
+		err = wait_event_interruptible_timeout(
+			apm_suspend_waitqueue,
+			atomic_read(&suspend_acks_pending) == 0,
+			5*HZ);
+
+		/* timed out */
+		if (err == 0) {
+			/*
+			 * Move anybody who timed out to "ack timeout" state.
+			 *
+			 * We could time out and the userspace does the ACK
+			 * right after we time out but before we enter the
+			 * locked section here, but that's fine.
+			 */
+			mutex_lock(&state_lock);
+			down_read(&user_list_lock);
+			list_for_each_entry(as, &apm_user_list, list) {
+				if (as->suspend_state == SUSPEND_PENDING ||
+				    as->suspend_state == SUSPEND_READ) {
+					as->suspend_state = SUSPEND_ACKTO;
+					atomic_dec(&suspend_acks_pending);
+				}
+			}
+			up_read(&user_list_lock);
+			mutex_unlock(&state_lock);
+		}
+
+		/* let suspend proceed */
+		if (err >= 0)
+			return NOTIFY_OK;
+
+		/* interrupted by signal */
+		return NOTIFY_BAD;
+
+	case PM_POST_SUSPEND:
+		/*
+		 * Anyone on the APM queues will think we're still suspended.
+		 * Send a message so everyone knows we're now awake again.
+		 */
+		queue_event(APM_NORMAL_RESUME);
+
+		/*
+		 * Finally, wake up anyone who is sleeping on the suspend.
+		 */
+		mutex_lock(&state_lock);
+		down_read(&user_list_lock);
+		list_for_each_entry(as, &apm_user_list, list) {
+			if (as->suspend_state == SUSPEND_ACKED) {
+				/*
+				 * TODO: maybe grab error code, needs core
+				 * changes to push the error to the notifier
+				 * chain (could use the second parameter if
+				 * implemented)
+				 */
+				as->suspend_result = 0;
+				as->suspend_state = SUSPEND_DONE;
+			}
+		}
+		up_read(&user_list_lock);
+		mutex_unlock(&state_lock);
+
+		wake_up(&apm_suspend_waitqueue);
+		return NOTIFY_OK;
+
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
+static struct notifier_block apm_notif_block = {
+	.notifier_call = apm_suspend_notifier,
+};
+
 static int __init apm_init(void)
 {
 	int ret;
@@ -601,7 +658,7 @@ static int __init apm_init(void)
 	if (IS_ERR(kapmd_tsk)) {
 		ret = PTR_ERR(kapmd_tsk);
 		kapmd_tsk = NULL;
-		return ret;
+		goto out;
 	}
 	wake_up_process(kapmd_tsk);
 
@@ -610,16 +667,27 @@ static int __init apm_init(void)
 #endif
 
 	ret = misc_register(&apm_device);
-	if (ret != 0) {
-		remove_proc_entry("apm", NULL);
-		kthread_stop(kapmd_tsk);
-	}
+	if (ret)
+		goto out_stop;
 
+	ret = register_pm_notifier(&apm_notif_block);
+	if (ret)
+		goto out_unregister;
+
+	return 0;
+
+ out_unregister:
+	misc_deregister(&apm_device);
+ out_stop:
+	remove_proc_entry("apm", NULL);
+	kthread_stop(kapmd_tsk);
+ out:
 	return ret;
 }
 
 static void __exit apm_exit(void)
 {
+	unregister_pm_notifier(&apm_notif_block);
 	misc_deregister(&apm_device);
 	remove_proc_entry("apm", NULL);
 

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

* [PATCH 3/4] ACPI PM: acpi_pm_device_sleep_state() cleanup
  2008-05-06 21:31 [PATCH 0/4] Patches for 2.6.27 Rafael J. Wysocki
  2008-05-06 21:33 ` [PATCH 1/4] ACPI Hibernation: Use ACPI hardware signature Rafael J. Wysocki
  2008-05-06 21:35 ` [PATCH 2/4] APM emulation: Notify about all suspend events, not just APM invoked ones (v2) Rafael J. Wysocki
@ 2008-05-06 21:37 ` Rafael J. Wysocki
  2008-05-06 21:38 ` [PATCH 4/4] PCI ACPI: Drop the second argument of platform_pci_choose_state Rafael J. Wysocki
  3 siblings, 0 replies; 11+ messages in thread
From: Rafael J. Wysocki @ 2008-05-06 21:37 UTC (permalink / raw)
  To: Len Brown
  Cc: ACPI Devel Maling List, pm list, Pavel Machek, Johannes Berg,
	Shaohua Li, David Brownell, Jesse Barnes

From: David Brownell <dbrownell@users.sourceforge.net>

Get rid of a superfluous acpi_pm_device_sleep_state() parameter.  The
only legitimate value of that parameter must be derived from the first
parameter, which is what all the callers already do.  (However, this
does not address the fact that ACPI still doesn't set up those flags.)

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/acpi/sleep/main.c  |    8 ++++----
 drivers/pci/pci-acpi.c     |    3 +--
 drivers/pnp/pnpacpi/core.c |    4 +---
 include/acpi/acpi_bus.h    |    4 ++--
 4 files changed, 8 insertions(+), 11 deletions(-)

Index: linux-2.6/drivers/acpi/sleep/main.c
===================================================================
--- linux-2.6.orig/drivers/acpi/sleep/main.c
+++ linux-2.6/drivers/acpi/sleep/main.c
@@ -386,8 +386,8 @@ int acpi_suspend(u32 acpi_state)
 /**
  *	acpi_pm_device_sleep_state - return preferred power state of ACPI device
  *		in the system sleep state given by %acpi_target_sleep_state
- *	@dev: device to examine
- *	@wake: if set, the device should be able to wake up the system
+ *	@dev: device to examine; its driver model wakeup flags control
+ *		whether it should be able to wake up the system
  *	@d_min_p: used to store the upper limit of allowed states range
  *	Return value: preferred power state of the device on success, -ENODEV on
  *		failure (ie. if there's no 'struct acpi_device' for @dev)
@@ -405,7 +405,7 @@ int acpi_suspend(u32 acpi_state)
  *	via @wake.
  */
 
-int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
+int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
 {
 	acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
 	struct acpi_device *adev;
@@ -444,7 +444,7 @@ int acpi_pm_device_sleep_state(struct de
 	 * can wake the system.  _S0W may be valid, too.
 	 */
 	if (acpi_target_sleep_state == ACPI_STATE_S0 ||
-	    (wake && adev->wakeup.state.enabled &&
+	    (device_may_wakeup(dev) && adev->wakeup.state.enabled &&
 	     adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
 		acpi_status status;
 
Index: linux-2.6/drivers/pci/pci-acpi.c
===================================================================
--- linux-2.6.orig/drivers/pci/pci-acpi.c
+++ linux-2.6/drivers/pci/pci-acpi.c
@@ -249,8 +249,7 @@ static pci_power_t acpi_pci_choose_state
 {
 	int acpi_state;
 
-	acpi_state = acpi_pm_device_sleep_state(&pdev->dev,
-		device_may_wakeup(&pdev->dev), NULL);
+	acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL);
 	if (acpi_state < 0)
 		return PCI_POWER_ERROR;
 
Index: linux-2.6/drivers/pnp/pnpacpi/core.c
===================================================================
--- linux-2.6.orig/drivers/pnp/pnpacpi/core.c
+++ linux-2.6/drivers/pnp/pnpacpi/core.c
@@ -117,9 +117,7 @@ static int pnpacpi_suspend(struct pnp_de
 {
 	int power_state;
 
-	power_state = acpi_pm_device_sleep_state(&dev->dev,
-						device_may_wakeup(&dev->dev),
-						NULL);
+	power_state = acpi_pm_device_sleep_state(&dev->dev, NULL);
 	if (power_state < 0)
 		power_state = (state.event == PM_EVENT_ON) ?
 				ACPI_STATE_D0 : ACPI_STATE_D3;
Index: linux-2.6/include/acpi/acpi_bus.h
===================================================================
--- linux-2.6.orig/include/acpi/acpi_bus.h
+++ linux-2.6/include/acpi/acpi_bus.h
@@ -376,9 +376,9 @@ acpi_handle acpi_get_pci_rootbridge_hand
 #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle))
 
 #ifdef CONFIG_PM_SLEEP
-int acpi_pm_device_sleep_state(struct device *, int, int *);
+int acpi_pm_device_sleep_state(struct device *, int *);
 #else /* !CONFIG_PM_SLEEP */
-static inline int acpi_pm_device_sleep_state(struct device *d, int w, int *p)
+static inline int acpi_pm_device_sleep_state(struct device *d, int *p)
 {
 	if (p)
 		*p = ACPI_STATE_D0;


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

* [PATCH 4/4] PCI ACPI: Drop the second argument of platform_pci_choose_state
  2008-05-06 21:31 [PATCH 0/4] Patches for 2.6.27 Rafael J. Wysocki
                   ` (2 preceding siblings ...)
  2008-05-06 21:37 ` [PATCH 3/4] ACPI PM: acpi_pm_device_sleep_state() cleanup Rafael J. Wysocki
@ 2008-05-06 21:38 ` Rafael J. Wysocki
  2008-05-07  9:24   ` Pavel Machek
  3 siblings, 1 reply; 11+ messages in thread
From: Rafael J. Wysocki @ 2008-05-06 21:38 UTC (permalink / raw)
  To: Len Brown
  Cc: ACPI Devel Maling List, pm list, Pavel Machek, Johannes Berg,
	Shaohua Li, David Brownell, Jesse Barnes

From: Rafael J. Wysocki <rjw@sisk.pl>

Since the second argument of acpi_pci_choose_state() and
platform_pci_choose_state() is never used, so remove it.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/pci/pci-acpi.c |    3 +--
 drivers/pci/pci.c      |    4 ++--
 drivers/pci/pci.h      |    3 +--
 3 files changed, 4 insertions(+), 6 deletions(-)

Index: linux-2.6/drivers/pci/pci-acpi.c
===================================================================
--- linux-2.6.orig/drivers/pci/pci-acpi.c
+++ linux-2.6/drivers/pci/pci-acpi.c
@@ -244,8 +244,7 @@ EXPORT_SYMBOL(pci_osc_control_set);
  * 	choose highest power _SxD or any lower power
  */
 
-static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev,
-	pm_message_t state)
+static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
 {
 	int acpi_state;
 
Index: linux-2.6/drivers/pci/pci.c
===================================================================
--- linux-2.6.orig/drivers/pci/pci.c
+++ linux-2.6/drivers/pci/pci.c
@@ -508,7 +508,7 @@ pci_set_power_state(struct pci_dev *dev,
 	return 0;
 }
 
-pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
+pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev);
  
 /**
  * pci_choose_state - Choose the power state of a PCI device
@@ -528,7 +528,7 @@ pci_power_t pci_choose_state(struct pci_
 		return PCI_D0;
 
 	if (platform_pci_choose_state) {
-		ret = platform_pci_choose_state(dev, state);
+		ret = platform_pci_choose_state(dev);
 		if (ret != PCI_POWER_ERROR)
 			return ret;
 	}
Index: linux-2.6/drivers/pci/pci.h
===================================================================
--- linux-2.6.orig/drivers/pci/pci.h
+++ linux-2.6/drivers/pci/pci.h
@@ -6,8 +6,7 @@ extern void pci_remove_sysfs_dev_files(s
 extern void pci_cleanup_rom(struct pci_dev *dev);
 
 /* Firmware callbacks */
-extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev,
-						pm_message_t state);
+extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev);
 extern int (*platform_pci_set_power_state)(struct pci_dev *dev,
 						pci_power_t state);
 

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

* Re: [PATCH 1/4] ACPI Hibernation: Use ACPI hardware signature
  2008-05-06 21:33 ` [PATCH 1/4] ACPI Hibernation: Use ACPI hardware signature Rafael J. Wysocki
@ 2008-05-07  9:20   ` Pavel Machek
  2008-05-07 12:28     ` Rafael J. Wysocki
  0 siblings, 1 reply; 11+ messages in thread
From: Pavel Machek @ 2008-05-07  9:20 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, ACPI Devel Maling List, pm list, Johannes Berg,
	Shaohua Li, David Brownell, Jesse Barnes

Hi!

> From: Shaohua Li <shaohua.li@intel.com>
> 
> ACPI defines a hardware signature. BIOS calculates the signature
> according to hardware configure, if hardware changes, the signature
> will change, in this case, S4 resume should fail.
> 
> Signed-off-by: Shaohua Li <shaohua.li@intel.com>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
> ---
>  drivers/acpi/sleep/main.c |   24 ++++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
> 
> Index: linux-2.6/drivers/acpi/sleep/main.c
> ===================================================================
> --- linux-2.6.orig/drivers/acpi/sleep/main.c
> +++ linux-2.6/drivers/acpi/sleep/main.c
> @@ -255,6 +255,17 @@ static struct dmi_system_id __initdata a
>  #endif /* CONFIG_SUSPEND */
>  
>  #ifdef CONFIG_HIBERNATION
> +static unsigned long s4_hardware_signature;
> +static struct acpi_table_facs *facs;
> +static bool nosigcheck;
> +
> +static int __init acpi_s4_nosigcheck(char *str)
> +{
> +	nosigcheck = true;
> +	return 1;
> +}
> +__setup("acpi_s4_nosigcheck", acpi_s4_nosigcheck);
> +

Needs a patch to Documentation/ , too.

>  static int acpi_hibernation_begin(void)
>  {
>  	acpi_target_sleep_state = ACPI_STATE_S4;
> @@ -301,6 +312,12 @@ static void acpi_hibernation_leave(void)
>  	acpi_enable();
>  	/* Reprogram control registers and execute _BFS */
>  	acpi_leave_sleep_state_prep(ACPI_STATE_S4);
> +	/* Check the hardware signature */
> +	if (facs && s4_hardware_signature != facs->hardware_signature)

do you need && !nosigcheck here ?

> +		printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
> +			"cannot resume!\n");
> +		panic("ACPI S4 hardware signature mismatch");
> +	}
>  }
>  
>  static void acpi_hibernation_finish(void)

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCH 2/4] APM emulation: Notify about all suspend events, not just APM invoked ones (v2)
  2008-05-06 21:35 ` [PATCH 2/4] APM emulation: Notify about all suspend events, not just APM invoked ones (v2) Rafael J. Wysocki
@ 2008-05-07  9:22   ` Pavel Machek
  0 siblings, 0 replies; 11+ messages in thread
From: Pavel Machek @ 2008-05-07  9:22 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, ACPI Devel Maling List, pm list, Johannes Berg,
	Shaohua Li, David Brownell, Jesse Barnes

Hi!

> From: Johannes Berg <johannes@sipsolutions.net>
> 
> This revamps the apm-emulation code to get suspend notifications
> regardless of what way pm_suspend() was invoked, whether via the
> apm ioctl or via /sys/power/state. Also do some code cleanup and
> add comments while at it.

Please always do cleanups & comment adds _before_ changing the code.

This is probably okay, but... it is quite hard to tell.


> Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>


> ---
> 
>  drivers/char/apm-emulation.c |  346 +++++++++++++++++++++++++------------------
>  1 file changed, 207 insertions(+), 139 deletions(-)
> 
> Index: linux-2.6/drivers/char/apm-emulation.c
> ===================================================================
> --- linux-2.6.orig/drivers/char/apm-emulation.c
> +++ linux-2.6/drivers/char/apm-emulation.c
> @@ -58,6 +58,55 @@ struct apm_queue {
>  };
>  
>  /*
> + * thread states (for threads using a writable /dev/apm_bios fd):
> + *
> + * SUSPEND_NONE:	nothing happening
> + * SUSPEND_PENDING:	suspend event queued for thread and pending to be read
> + * SUSPEND_READ:	suspend event read, pending acknowledgement
> + * SUSPEND_ACKED:	acknowledgement received from thread (via ioctl),
> + *			waiting for resume
> + * SUSPEND_ACKTO:	acknowledgement timeout
> + * SUSPEND_DONE:	thread had acked suspend and is now notified of
> + *			resume
> + *
> + * SUSPEND_WAIT:	this thread invoked suspend and is waiting for resume
> + *
> + * A thread migrates in one of three paths:
> + * 	NONE -1-> PENDING -2-> READ -3-> ACKED -4-> DONE -5-> NONE
> + *	                            -6-> ACKTO -7-> NONE
> + *	NONE -8-> WAIT -9-> NONE
> + *
> + * While in PENDING or READ, the thread is accounted for in the
> + * suspend_acks_pending counter.
> + *
> + * The transitions are invoked as follows:
> + *	1: suspend event is signalled from the core PM code
> + *	2: the suspend event is read from the fd by the userspace thread
> + *	3: userspace thread issues the APM_IOC_SUSPEND ioctl (as ack)
> + *	4: core PM code signals that we have resumed
> + *	5: APM_IOC_SUSPEND ioctl returns
> + *
> + *	6: the notifier invoked from the core PM code timed out waiting
> + *	   for all relevant threds to enter ACKED state and puts those
> + *	   that haven't into ACKTO
> + *	7: those threads issue APM_IOC_SUSPEND ioctl too late,
> + *	   get an error
> + *
> + *	8: userspace thread issues the APM_IOC_SUSPEND ioctl (to suspend),
> + *	   ioctl code invokes pm_suspend()
> + *	9: pm_suspend() returns indicating resume
> + */
> +enum apm_suspend_state {
> +	SUSPEND_NONE,
> +	SUSPEND_PENDING,
> +	SUSPEND_READ,
> +	SUSPEND_ACKED,
> +	SUSPEND_ACKTO,
> +	SUSPEND_WAIT,
> +	SUSPEND_DONE,
> +};
> +
> +/*
>   * The per-file APM data
>   */
>  struct apm_user {
> @@ -68,13 +117,7 @@ struct apm_user {
>  	unsigned int		reader: 1;
>  
>  	int			suspend_result;
> -	unsigned int		suspend_state;
> -#define SUSPEND_NONE	0		/* no suspend pending */
> -#define SUSPEND_PENDING	1		/* suspend pending read */
> -#define SUSPEND_READ	2		/* suspend read, pending ack */
> -#define SUSPEND_ACKED	3		/* suspend acked */
> -#define SUSPEND_WAIT	4		/* waiting for suspend */
> -#define SUSPEND_DONE	5		/* suspend completed */
> +	enum apm_suspend_state	suspend_state;
>  
>  	struct apm_queue	queue;
>  };
> @@ -82,7 +125,8 @@ struct apm_user {
>  /*
>   * Local variables
>   */
> -static int suspends_pending;
> +static atomic_t suspend_acks_pending = ATOMIC_INIT(0);
> +static atomic_t userspace_notification_inhibit = ATOMIC_INIT(0);
>  static int apm_disabled;
>  static struct task_struct *kapmd_tsk;
>  
> @@ -165,78 +209,6 @@ static void queue_event(apm_event_t even
>  	wake_up_interruptible(&apm_waitqueue);
>  }
>  
> -/*
> - * queue_suspend_event - queue an APM suspend event.
> - *
> - * Check that we're in a state where we can suspend.  If not,
> - * return -EBUSY.  Otherwise, queue an event to all "writer"
> - * users.  If there are no "writer" users, return '1' to
> - * indicate that we can immediately suspend.
> - */
> -static int queue_suspend_event(apm_event_t event, struct apm_user *sender)
> -{
> -	struct apm_user *as;
> -	int ret = 1;
> -
> -	mutex_lock(&state_lock);
> -	down_read(&user_list_lock);
> -
> -	/*
> -	 * If a thread is still processing, we can't suspend, so reject
> -	 * the request.
> -	 */
> -	list_for_each_entry(as, &apm_user_list, list) {
> -		if (as != sender && as->reader && as->writer && as->suser &&
> -		    as->suspend_state != SUSPEND_NONE) {
> -			ret = -EBUSY;
> -			goto out;
> -		}
> -	}
> -
> -	list_for_each_entry(as, &apm_user_list, list) {
> -		if (as != sender && as->reader && as->writer && as->suser) {
> -			as->suspend_state = SUSPEND_PENDING;
> -			suspends_pending++;
> -			queue_add_event(&as->queue, event);
> -			ret = 0;
> -		}
> -	}
> - out:
> -	up_read(&user_list_lock);
> -	mutex_unlock(&state_lock);
> -	wake_up_interruptible(&apm_waitqueue);
> -	return ret;
> -}
> -
> -static void apm_suspend(void)
> -{
> -	struct apm_user *as;
> -	int err = pm_suspend(PM_SUSPEND_MEM);
> -
> -	/*
> -	 * Anyone on the APM queues will think we're still suspended.
> -	 * Send a message so everyone knows we're now awake again.
> -	 */
> -	queue_event(APM_NORMAL_RESUME);
> -
> -	/*
> -	 * Finally, wake up anyone who is sleeping on the suspend.
> -	 */
> -	mutex_lock(&state_lock);
> -	down_read(&user_list_lock);
> -	list_for_each_entry(as, &apm_user_list, list) {
> -		if (as->suspend_state == SUSPEND_WAIT ||
> -		    as->suspend_state == SUSPEND_ACKED) {
> -			as->suspend_result = err;
> -			as->suspend_state = SUSPEND_DONE;
> -		}
> -	}
> -	up_read(&user_list_lock);
> -	mutex_unlock(&state_lock);
> -
> -	wake_up(&apm_suspend_waitqueue);
> -}
> -
>  static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
>  {
>  	struct apm_user *as = fp->private_data;
> @@ -307,25 +279,22 @@ apm_ioctl(struct inode * inode, struct f
>  
>  		as->suspend_result = -EINTR;
>  
> -		if (as->suspend_state == SUSPEND_READ) {
> -			int pending;
> -
> +		switch (as->suspend_state) {
> +		case SUSPEND_READ:
>  			/*
>  			 * If we read a suspend command from /dev/apm_bios,
>  			 * then the corresponding APM_IOC_SUSPEND ioctl is
>  			 * interpreted as an acknowledge.
>  			 */
>  			as->suspend_state = SUSPEND_ACKED;
> -			suspends_pending--;
> -			pending = suspends_pending == 0;
> +			atomic_dec(&suspend_acks_pending);
>  			mutex_unlock(&state_lock);
>  
>  			/*
> -			 * If there are no further acknowledges required,
> -			 * suspend the system.
> +			 * suspend_acks_pending changed, the notifier needs to
> +			 * be woken up for this
>  			 */
> -			if (pending)
> -				apm_suspend();
> +			wake_up(&apm_suspend_waitqueue);
>  
>  			/*
>  			 * Wait for the suspend/resume to complete.  If there
> @@ -341,35 +310,21 @@ apm_ioctl(struct inode * inode, struct f
>  			 * try_to_freeze() in freezer_count() will not trigger
>  			 */
>  			freezer_count();
> -		} else {
> +			break;
> +		case SUSPEND_ACKTO:
> +			as->suspend_result = -ETIMEDOUT;
> +			mutex_unlock(&state_lock);
> +			break;
> +		default:
>  			as->suspend_state = SUSPEND_WAIT;
>  			mutex_unlock(&state_lock);
>  
>  			/*
>  			 * Otherwise it is a request to suspend the system.
> -			 * Queue an event for all readers, and expect an
> -			 * acknowledge from all writers who haven't already
> -			 * acknowledged.
> -			 */
> -			err = queue_suspend_event(APM_USER_SUSPEND, as);
> -			if (err < 0) {
> -				/*
> -				 * Avoid taking the lock here - this
> -				 * should be fine.
> -				 */
> -				as->suspend_state = SUSPEND_NONE;
> -				break;
> -			}
> -
> -			if (err > 0)
> -				apm_suspend();
> -
> -			/*
> -			 * Wait for the suspend/resume to complete.  If there
> -			 * are pending acknowledges, we wait here for them.
> +			 * Just invoke pm_suspend(), we'll handle it from
> +			 * there via the notifier.
>  			 */
> -			wait_event_freezable(apm_suspend_waitqueue,
> -					 as->suspend_state == SUSPEND_DONE);
> +			as->suspend_result = pm_suspend(PM_SUSPEND_MEM);
>  		}
>  
>  		mutex_lock(&state_lock);
> @@ -385,7 +340,6 @@ apm_ioctl(struct inode * inode, struct f
>  static int apm_release(struct inode * inode, struct file * filp)
>  {
>  	struct apm_user *as = filp->private_data;
> -	int pending = 0;
>  
>  	filp->private_data = NULL;
>  
> @@ -395,18 +349,15 @@ static int apm_release(struct inode * in
>  
>  	/*
>  	 * We are now unhooked from the chain.  As far as new
> -	 * events are concerned, we no longer exist.  However, we
> -	 * need to balance suspends_pending, which means the
> -	 * possibility of sleeping.
> +	 * events are concerned, we no longer exist.
>  	 */
>  	mutex_lock(&state_lock);
> -	if (as->suspend_state != SUSPEND_NONE) {
> -		suspends_pending -= 1;
> -		pending = suspends_pending == 0;
> -	}
> +	if (as->suspend_state == SUSPEND_PENDING ||
> +	    as->suspend_state == SUSPEND_READ)
> +		atomic_dec(&suspend_acks_pending);
>  	mutex_unlock(&state_lock);
> -	if (pending)
> -		apm_suspend();
> +
> +	wake_up(&apm_suspend_waitqueue);
>  
>  	kfree(as);
>  	return 0;
> @@ -542,7 +493,6 @@ static int kapmd(void *arg)
>  {
>  	do {
>  		apm_event_t event;
> -		int ret;
>  
>  		wait_event_interruptible(kapmd_wait,
>  				!queue_empty(&kapmd_queue) || kthread_should_stop());
> @@ -567,20 +517,13 @@ static int kapmd(void *arg)
>  
>  		case APM_USER_SUSPEND:
>  		case APM_SYS_SUSPEND:
> -			ret = queue_suspend_event(event, NULL);
> -			if (ret < 0) {
> -				/*
> -				 * We were busy.  Try again in 50ms.
> -				 */
> -				queue_add_event(&kapmd_queue, event);
> -				msleep(50);
> -			}
> -			if (ret > 0)
> -				apm_suspend();
> +			pm_suspend(PM_SUSPEND_MEM);
>  			break;
>  
>  		case APM_CRITICAL_SUSPEND:
> -			apm_suspend();
> +			atomic_inc(&userspace_notification_inhibit);
> +			pm_suspend(PM_SUSPEND_MEM);
> +			atomic_dec(&userspace_notification_inhibit);
>  			break;
>  		}
>  	} while (1);
> @@ -588,6 +531,120 @@ static int kapmd(void *arg)
>  	return 0;
>  }
>  
> +static int apm_suspend_notifier(struct notifier_block *nb,
> +				unsigned long event,
> +				void *dummy)
> +{
> +	struct apm_user *as;
> +	int err;
> +
> +	/* short-cut emergency suspends */
> +	if (atomic_read(&userspace_notification_inhibit))
> +		return NOTIFY_DONE;
> +
> +	switch (event) {
> +	case PM_SUSPEND_PREPARE:
> +		/*
> +		 * Queue an event to all "writer" users that we want
> +		 * to suspend and need their ack.
> +		 */
> +		mutex_lock(&state_lock);
> +		down_read(&user_list_lock);
> +
> +		list_for_each_entry(as, &apm_user_list, list) {
> +			if (as->suspend_state != SUSPEND_WAIT && as->reader &&
> +			    as->writer && as->suser) {
> +				as->suspend_state = SUSPEND_PENDING;
> +				atomic_inc(&suspend_acks_pending);
> +				queue_add_event(&as->queue, APM_USER_SUSPEND);
> +			}
> +		}
> +
> +		up_read(&user_list_lock);
> +		mutex_unlock(&state_lock);
> +		wake_up_interruptible(&apm_waitqueue);
> +
> +		/*
> +		 * Wait for the the suspend_acks_pending variable to drop to
> +		 * zero, meaning everybody acked the suspend event (or the
> +		 * process was killed.)
> +		 *
> +		 * If the app won't answer within a short while we assume it
> +		 * locked up and ignore it.
> +		 */
> +		err = wait_event_interruptible_timeout(
> +			apm_suspend_waitqueue,
> +			atomic_read(&suspend_acks_pending) == 0,
> +			5*HZ);
> +
> +		/* timed out */
> +		if (err == 0) {
> +			/*
> +			 * Move anybody who timed out to "ack timeout" state.
> +			 *
> +			 * We could time out and the userspace does the ACK
> +			 * right after we time out but before we enter the
> +			 * locked section here, but that's fine.
> +			 */
> +			mutex_lock(&state_lock);
> +			down_read(&user_list_lock);
> +			list_for_each_entry(as, &apm_user_list, list) {
> +				if (as->suspend_state == SUSPEND_PENDING ||
> +				    as->suspend_state == SUSPEND_READ) {
> +					as->suspend_state = SUSPEND_ACKTO;
> +					atomic_dec(&suspend_acks_pending);
> +				}
> +			}
> +			up_read(&user_list_lock);
> +			mutex_unlock(&state_lock);
> +		}
> +
> +		/* let suspend proceed */
> +		if (err >= 0)
> +			return NOTIFY_OK;
> +
> +		/* interrupted by signal */
> +		return NOTIFY_BAD;
> +
> +	case PM_POST_SUSPEND:
> +		/*
> +		 * Anyone on the APM queues will think we're still suspended.
> +		 * Send a message so everyone knows we're now awake again.
> +		 */
> +		queue_event(APM_NORMAL_RESUME);
> +
> +		/*
> +		 * Finally, wake up anyone who is sleeping on the suspend.
> +		 */
> +		mutex_lock(&state_lock);
> +		down_read(&user_list_lock);
> +		list_for_each_entry(as, &apm_user_list, list) {
> +			if (as->suspend_state == SUSPEND_ACKED) {
> +				/*
> +				 * TODO: maybe grab error code, needs core
> +				 * changes to push the error to the notifier
> +				 * chain (could use the second parameter if
> +				 * implemented)
> +				 */
> +				as->suspend_result = 0;
> +				as->suspend_state = SUSPEND_DONE;
> +			}
> +		}
> +		up_read(&user_list_lock);
> +		mutex_unlock(&state_lock);
> +
> +		wake_up(&apm_suspend_waitqueue);
> +		return NOTIFY_OK;
> +
> +	default:
> +		return NOTIFY_DONE;
> +	}
> +}
> +
> +static struct notifier_block apm_notif_block = {
> +	.notifier_call = apm_suspend_notifier,
> +};
> +
>  static int __init apm_init(void)
>  {
>  	int ret;
> @@ -601,7 +658,7 @@ static int __init apm_init(void)
>  	if (IS_ERR(kapmd_tsk)) {
>  		ret = PTR_ERR(kapmd_tsk);
>  		kapmd_tsk = NULL;
> -		return ret;
> +		goto out;
>  	}
>  	wake_up_process(kapmd_tsk);
>  
> @@ -610,16 +667,27 @@ static int __init apm_init(void)
>  #endif
>  
>  	ret = misc_register(&apm_device);
> -	if (ret != 0) {
> -		remove_proc_entry("apm", NULL);
> -		kthread_stop(kapmd_tsk);
> -	}
> +	if (ret)
> +		goto out_stop;
>  
> +	ret = register_pm_notifier(&apm_notif_block);
> +	if (ret)
> +		goto out_unregister;
> +
> +	return 0;
> +
> + out_unregister:
> +	misc_deregister(&apm_device);
> + out_stop:
> +	remove_proc_entry("apm", NULL);
> +	kthread_stop(kapmd_tsk);
> + out:
>  	return ret;
>  }
>  
>  static void __exit apm_exit(void)
>  {
> +	unregister_pm_notifier(&apm_notif_block);
>  	misc_deregister(&apm_device);
>  	remove_proc_entry("apm", NULL);
>  

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCH 4/4] PCI ACPI: Drop the second argument of platform_pci_choose_state
  2008-05-06 21:38 ` [PATCH 4/4] PCI ACPI: Drop the second argument of platform_pci_choose_state Rafael J. Wysocki
@ 2008-05-07  9:24   ` Pavel Machek
  0 siblings, 0 replies; 11+ messages in thread
From: Pavel Machek @ 2008-05-07  9:24 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, ACPI Devel Maling List, pm list, Johannes Berg,
	Shaohua Li, David Brownell, Jesse Barnes

On Tue 2008-05-06 23:38:41, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
> 
> Since the second argument of acpi_pci_choose_state() and
> platform_pci_choose_state() is never used, so remove it.
> 
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>

ACK.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCH 1/4] ACPI Hibernation: Use ACPI hardware signature
  2008-05-07  9:20   ` Pavel Machek
@ 2008-05-07 12:28     ` Rafael J. Wysocki
  2008-05-07 21:04       ` Pavel Machek
  0 siblings, 1 reply; 11+ messages in thread
From: Rafael J. Wysocki @ 2008-05-07 12:28 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Len Brown, ACPI Devel Maling List, pm list, Johannes Berg,
	Shaohua Li, David Brownell, Jesse Barnes

On Wednesday, 7 of May 2008, Pavel Machek wrote:
> Hi!

Hi,

> > From: Shaohua Li <shaohua.li@intel.com>
> > 
> > ACPI defines a hardware signature. BIOS calculates the signature
> > according to hardware configure, if hardware changes, the signature
> > will change, in this case, S4 resume should fail.
> > 
> > Signed-off-by: Shaohua Li <shaohua.li@intel.com>
> > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
> > ---
> >  drivers/acpi/sleep/main.c |   24 ++++++++++++++++++++++++
> >  1 file changed, 24 insertions(+)
> > 
> > Index: linux-2.6/drivers/acpi/sleep/main.c
> > ===================================================================
> > --- linux-2.6.orig/drivers/acpi/sleep/main.c
> > +++ linux-2.6/drivers/acpi/sleep/main.c
> > @@ -255,6 +255,17 @@ static struct dmi_system_id __initdata a
> >  #endif /* CONFIG_SUSPEND */
> >  
> >  #ifdef CONFIG_HIBERNATION
> > +static unsigned long s4_hardware_signature;
> > +static struct acpi_table_facs *facs;
> > +static bool nosigcheck;
> > +
> > +static int __init acpi_s4_nosigcheck(char *str)
> > +{
> > +	nosigcheck = true;
> > +	return 1;
> > +}
> > +__setup("acpi_s4_nosigcheck", acpi_s4_nosigcheck);
> > +
> 
> Needs a patch to Documentation/ , too.

Yes, thanks.

> >  static int acpi_hibernation_begin(void)
> >  {
> >  	acpi_target_sleep_state = ACPI_STATE_S4;
> > @@ -301,6 +312,12 @@ static void acpi_hibernation_leave(void)
> >  	acpi_enable();
> >  	/* Reprogram control registers and execute _BFS */
> >  	acpi_leave_sleep_state_prep(ACPI_STATE_S4);
> > +	/* Check the hardware signature */
> > +	if (facs && s4_hardware_signature != facs->hardware_signature)
> 
> do you need && !nosigcheck here ?

No, facs is NULL if !nosigcheck.

> > +		printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
> > +			"cannot resume!\n");
> > +		panic("ACPI S4 hardware signature mismatch");
> > +	}
> >  }
> >  
> >  static void acpi_hibernation_finish(void)
> 

Thanks,
Rafael

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

* Re: [PATCH 1/4] ACPI Hibernation: Use ACPI hardware signature
  2008-05-07 12:28     ` Rafael J. Wysocki
@ 2008-05-07 21:04       ` Pavel Machek
  2008-05-09 15:27         ` Rafael J. Wysocki
  0 siblings, 1 reply; 11+ messages in thread
From: Pavel Machek @ 2008-05-07 21:04 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, ACPI Devel Maling List, pm list, Johannes Berg,
	Shaohua Li, David Brownell, Jesse Barnes

Hi!

> > > +static int __init acpi_s4_nosigcheck(char *str)
> > > +{
> > > +	nosigcheck = true;
> > > +	return 1;
> > > +}
> > > +__setup("acpi_s4_nosigcheck", acpi_s4_nosigcheck);
> > > +
> > 
> > Needs a patch to Documentation/ , too.
> 
> Yes, thanks.
> 
> > > +	/* Check the hardware signature */
> > > +	if (facs && s4_hardware_signature != facs->hardware_signature)
> > 
> > do you need && !nosigcheck here ?
> 
> No, facs is NULL if !nosigcheck.

Aha, ook. You can add my ACK when you add the Documentation/.

									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCH 1/4] ACPI Hibernation: Use ACPI hardware signature
  2008-05-07 21:04       ` Pavel Machek
@ 2008-05-09 15:27         ` Rafael J. Wysocki
  0 siblings, 0 replies; 11+ messages in thread
From: Rafael J. Wysocki @ 2008-05-09 15:27 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Len Brown, ACPI Devel Maling List, pm list, Johannes Berg,
	Shaohua Li, David Brownell, Jesse Barnes

On Wednesday, 7 of May 2008, Pavel Machek wrote:
> Hi!

Hi,

> > > > +static int __init acpi_s4_nosigcheck(char *str)
> > > > +{
> > > > +	nosigcheck = true;
> > > > +	return 1;
> > > > +}
> > > > +__setup("acpi_s4_nosigcheck", acpi_s4_nosigcheck);
> > > > +
> > > 
> > > Needs a patch to Documentation/ , too.
> > 
> > Yes, thanks.
> > 
> > > > +	/* Check the hardware signature */
> > > > +	if (facs && s4_hardware_signature != facs->hardware_signature)
> > > 
> > > do you need && !nosigcheck here ?
> > 
> > No, facs is NULL if !nosigcheck.
> 
> Aha, ook. You can add my ACK when you add the Documentation/.

Corrected patch is appended.

Thanks,
Rafael

---
From: Shaohua Li <shaohua.li@intel.com>

ACPI defines a hardware signature. BIOS calculates the signature
according to hardware configure, if hardware changes, the signature
will change, in this case, S4 resume should fail.

[rjw: The kernel command line switch acpi_s4_nosigcheck is added for
systems on which this mechanism is broken.]

Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Acked-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 Documentation/kernel-parameters.txt |    5 +++++
 drivers/acpi/sleep/main.c           |   24 ++++++++++++++++++++++++
 2 files changed, 29 insertions(+)

Index: linux-2.6/drivers/acpi/sleep/main.c
===================================================================
--- linux-2.6.orig/drivers/acpi/sleep/main.c
+++ linux-2.6/drivers/acpi/sleep/main.c
@@ -255,6 +255,17 @@ static struct dmi_system_id __initdata a
 #endif /* CONFIG_SUSPEND */
 
 #ifdef CONFIG_HIBERNATION
+static unsigned long s4_hardware_signature;
+static struct acpi_table_facs *facs;
+static bool nosigcheck;
+
+static int __init acpi_s4_nosigcheck(char *str)
+{
+	nosigcheck = true;
+	return 1;
+}
+__setup("acpi_s4_nosigcheck", acpi_s4_nosigcheck);
+
 static int acpi_hibernation_begin(void)
 {
 	acpi_target_sleep_state = ACPI_STATE_S4;
@@ -301,6 +312,12 @@ static void acpi_hibernation_leave(void)
 	acpi_enable();
 	/* Reprogram control registers and execute _BFS */
 	acpi_leave_sleep_state_prep(ACPI_STATE_S4);
+	/* Check the hardware signature */
+	if (facs && s4_hardware_signature != facs->hardware_signature) {
+		printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
+			"cannot resume!\n");
+		panic("ACPI S4 hardware signature mismatch");
+	}
 }
 
 static void acpi_hibernation_finish(void)
@@ -501,6 +518,13 @@ int __init acpi_sleep_init(void)
 		hibernation_set_ops(&acpi_hibernation_ops);
 		sleep_states[ACPI_STATE_S4] = 1;
 		printk(" S4");
+		if (!nosigcheck) {
+			acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+				(struct acpi_table_header **)&facs);
+			if (facs)
+				s4_hardware_signature =
+					facs->hardware_signature;
+		}
 	}
 #endif
 	status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
Index: linux-2.6/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.orig/Documentation/kernel-parameters.txt
+++ linux-2.6/Documentation/kernel-parameters.txt
@@ -152,6 +152,11 @@ and is between 256 and 4096 characters. 
 			s3_beep is for debugging; it makes the PC's speaker beep
 			as soon as the kernel's real-mode entry point is called.
 
+	acpi_s4_nosigcheck [HW,ACPI] S4 hardware signature
+			ACPI will ignore the S4 hardware signature
+			default: The hardware signature is checked during
+			         resume from S4.
+
 	acpi_sci=	[HW,ACPI] ACPI System Control Interrupt trigger mode
 			Format: { level | edge | high | low }
 

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

end of thread, other threads:[~2008-05-09 15:27 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-06 21:31 [PATCH 0/4] Patches for 2.6.27 Rafael J. Wysocki
2008-05-06 21:33 ` [PATCH 1/4] ACPI Hibernation: Use ACPI hardware signature Rafael J. Wysocki
2008-05-07  9:20   ` Pavel Machek
2008-05-07 12:28     ` Rafael J. Wysocki
2008-05-07 21:04       ` Pavel Machek
2008-05-09 15:27         ` Rafael J. Wysocki
2008-05-06 21:35 ` [PATCH 2/4] APM emulation: Notify about all suspend events, not just APM invoked ones (v2) Rafael J. Wysocki
2008-05-07  9:22   ` Pavel Machek
2008-05-06 21:37 ` [PATCH 3/4] ACPI PM: acpi_pm_device_sleep_state() cleanup Rafael J. Wysocki
2008-05-06 21:38 ` [PATCH 4/4] PCI ACPI: Drop the second argument of platform_pci_choose_state Rafael J. Wysocki
2008-05-07  9:24   ` Pavel Machek

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