| From 0a7992c90828a65281c3c9cf180be3b432d277b2 Mon Sep 17 00:00:00 2001 | 
 | From: Thomas Gleixner <tglx@linutronix.de> | 
 | Date: Wed, 11 Aug 2010 14:17:29 -0700 | 
 | Subject: acpi: fix bogus preemption logic | 
 |  | 
 | From: Thomas Gleixner <tglx@linutronix.de> | 
 |  | 
 | commit 0a7992c90828a65281c3c9cf180be3b432d277b2 upstream. | 
 |  | 
 | The ACPI_PREEMPTION_POINT() logic was introduced in commit 8bd108d | 
 | (ACPICA: add preemption point after each opcode parse).  The follow up | 
 | commits abe1dfab6, 138d15692, c084ca70 tried to fix the preemption logic | 
 | back and forth, but nobody noticed that the usage of | 
 | in_atomic_preempt_off() in that context is wrong. | 
 |  | 
 | The check which guards the call of cond_resched() is: | 
 |  | 
 |     if (!in_atomic_preempt_off() && !irqs_disabled()) | 
 |  | 
 | in_atomic_preempt_off() is not intended for general use as the comment | 
 | above the macro definition clearly says: | 
 |  | 
 |  * Check whether we were atomic before we did preempt_disable(): | 
 |  * (used by the scheduler, *after* releasing the kernel lock) | 
 |  | 
 | On a CONFIG_PREEMPT=n kernel the usage of in_atomic_preempt_off() works by | 
 | accident, but with CONFIG_PREEMPT=y it's just broken. | 
 |  | 
 | The whole purpose of the ACPI_PREEMPTION_POINT() is to reduce the latency | 
 | on a CONFIG_PREEMPT=n kernel, so make ACPI_PREEMPTION_POINT() depend on | 
 | CONFIG_PREEMPT=n and remove the in_atomic_preempt_off() check. | 
 |  | 
 | Addresses https://bugzilla.kernel.org/show_bug.cgi?id=16210 | 
 |  | 
 | [akpm@linux-foundation.org: fix build] | 
 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | 
 | Cc: Len Brown <lenb@kernel.org> | 
 | Cc: Francois Valenduc <francois.valenduc@tvcablenet.be> | 
 | Cc: Lin Ming <ming.m.lin@intel.com> | 
 | Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | 
 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | 
 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | 
 |  | 
 | --- | 
 |  drivers/acpi/apei/erst.c        |    1 + | 
 |  include/acpi/platform/aclinux.h |   10 +++++++--- | 
 |  2 files changed, 8 insertions(+), 3 deletions(-) | 
 |  | 
 | --- a/drivers/acpi/apei/erst.c | 
 | +++ b/drivers/acpi/apei/erst.c | 
 | @@ -33,6 +33,7 @@ | 
 |  #include <linux/uaccess.h> | 
 |  #include <linux/cper.h> | 
 |  #include <linux/nmi.h> | 
 | +#include <linux/hardirq.h> | 
 |  #include <acpi/apei.h> | 
 |   | 
 |  #include "apei-internal.h" | 
 | --- a/include/acpi/platform/aclinux.h | 
 | +++ b/include/acpi/platform/aclinux.h | 
 | @@ -148,13 +148,17 @@ static inline void *acpi_os_acquire_obje | 
 |  #define ACPI_ALLOCATE_ZEROED(a) acpi_os_allocate_zeroed(a) | 
 |  #define ACPI_FREE(a)            kfree(a) | 
 |   | 
 | -/* Used within ACPICA to show where it is safe to preempt execution */ | 
 | -#include <linux/hardirq.h> | 
 | +#ifndef CONFIG_PREEMPT | 
 | +/* | 
 | + * Used within ACPICA to show where it is safe to preempt execution | 
 | + * when CONFIG_PREEMPT=n | 
 | + */ | 
 |  #define ACPI_PREEMPTION_POINT() \ | 
 |  	do { \ | 
 | -		if (!in_atomic_preempt_off() && !irqs_disabled()) \ | 
 | +		if (!irqs_disabled()) \ | 
 |  			cond_resched(); \ | 
 |  	} while (0) | 
 | +#endif | 
 |   | 
 |  #endif /* __KERNEL__ */ | 
 |   |