summaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-07-09 02:54:55 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-07-09 02:54:55 +0000
commit493c987f7a352ca64fdb4dc03a21e24cbaf46f55 (patch)
tree184cddc0925e082c0500afd042f92e9f340fe890 /arch/i386
parent2d25612a92c62b5708d6d43f38d28c6141173328 (diff)
Merge with Linux 2.4.0-pre3-test6.
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/config.in4
-rw-r--r--arch/i386/kernel/apm.c2
-rw-r--r--arch/i386/lib/Makefile4
-rw-r--r--arch/i386/lib/dec_and_lock.c40
4 files changed, 50 insertions, 0 deletions
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 7344e802c..a2252d7af 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -34,6 +34,7 @@ choice 'Processor family' \
# Define implied options from the CPU selection here
#
if [ "$CONFIG_M386" = "y" ]; then
+ define_bool CONFIG_X86_CMPXCHG n
define_int CONFIG_X86_L1_CACHE_BYTES 16
else
define_bool CONFIG_X86_WP_WORKS_OK y
@@ -139,6 +140,9 @@ if [ "$CONFIG_SMP" != "y" ]; then
define_bool CONFIG_X86_LOCAL_APIC y
fi
fi
+if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
+ define_bool CONFIG_HAVE_DEC_LOCK y
+fi
endmenu
mainmenu_option next_comment
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index c78a8f512..6a4eedf72 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -660,6 +660,7 @@ static void apm_power_off(void)
#endif
}
+#ifdef CONFIG_APM_DO_ENABLE
static int apm_enable_power_management(int enable)
{
u32 eax;
@@ -675,6 +676,7 @@ static int apm_enable_power_management(int enable)
apm_bios_info.flags |= APM_BIOS_DISABLED;
return APM_SUCCESS;
}
+#endif
static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
{
diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile
index 2394245a6..be8fcec0a 100644
--- a/arch/i386/lib/Makefile
+++ b/arch/i386/lib/Makefile
@@ -13,4 +13,8 @@ ifdef CONFIG_X86_USE_3DNOW
L_OBJS += mmx.o
endif
+ifdef CONFIG_HAVE_DEC_LOCK
+L_OBJS += dec_and_lock.o
+endif
+
include $(TOPDIR)/Rules.make
diff --git a/arch/i386/lib/dec_and_lock.c b/arch/i386/lib/dec_and_lock.c
new file mode 100644
index 000000000..ffd486900
--- /dev/null
+++ b/arch/i386/lib/dec_and_lock.c
@@ -0,0 +1,40 @@
+/*
+ * x86 version of "atomic_dec_and_lock()" using
+ * the atomic "cmpxchg" instruction.
+ *
+ * (For CPU's lacking cmpxchg, we use the slow
+ * generic version, and this one never even gets
+ * compiled).
+ */
+
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+ int counter;
+ int newcount;
+
+repeat:
+ counter = atomic_read(atomic);
+ newcount = counter-1;
+
+ if (!newcount)
+ goto slow_path;
+
+ asm volatile("lock; cmpxchgl %1,%2"
+ :"=a" (newcount)
+ :"r" (newcount), "m" (atomic->counter), "0" (counter));
+
+ /* If the above failed, "eax" will have changed */
+ if (newcount != counter)
+ goto repeat;
+ return 0;
+
+slow_path:
+ spin_lock(lock);
+ if (atomic_dec_and_test(atomic))
+ return 1;
+ spin_unlock(lock);
+ return 0;
+}