From: David Howells <dhowells@redhat.com>
To: ralf@gnu.ai.mit.edu
Cc: linux-mips@fnet.fr, linux-kernel@vger.kernel.org
Subject: optimised rw-semaphores for MIPS/MIPS64
Date: Wed, 11 Jul 2001 15:00:47 +0100 [thread overview]
Message-ID: <2508.994860047@warthog.cambridge.redhat.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 441 bytes --]
Hello Ralf,
I've produced an inline-assembly optimised Read/Write Semaphore patch for MIPS
against linux-2.4.7-pre6 (rwsem.diff). David Woodhouse has tested it.
I've also included a patch to the MIPS64 arch to supply that with optimised
rwsems (rwsem64.diff), but that is untested.
Finally, I've included a patch to fix lib/rwsem.c (lib-rwsem.diff) if you want
to try the patch on MIPS64 against anything earlier than 2.4.7-pre6.
David
[-- Attachment #2: MIPS optimised rwsem patch --]
[-- Type: text/plain, Size: 5702 bytes --]
diff -uNr -x CVS -x TAGS linux-2.4-mips/arch/mips/config.in linux-mips-rwsem/arch/mips/config.in
--- linux-2.4-mips/arch/mips/config.in Thu Jun 28 13:58:46 2001
+++ linux-mips-rwsem/arch/mips/config.in Wed Jul 11 14:38:19 2001
@@ -68,8 +68,8 @@
fi
bool 'Support for Alchemy Semi PB1000 board' CONFIG_MIPS_PB1000
-define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
-define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
#
# Select some configuration options automatically for certain systems.
diff -uNr -x CVS -x TAGS linux-2.4-mips/include/asm-mips/rwsem.h linux-mips-rwsem/include/asm-mips/rwsem.h
--- linux-2.4-mips/include/asm-mips/rwsem.h Thu Jan 1 01:00:00 1970
+++ linux-mips-rwsem/include/asm-mips/rwsem.h Wed Jul 11 14:35:09 2001
@@ -0,0 +1,206 @@
+/* rwsem.h: R/W semaphores implemented using MIPS32 LL/SC
+ *
+ * Written by David Howells (dhowells@redhat.com).
+ *
+ * Derived from:
+ * - asm-i386/rwsem.h: written by David Howells (dhowells@redhat.com).
+ * - asm-alpha/rwsem.h: written by Ivan Kokshaysky <ink@jurassic.park.msu.ru>, 2001.
+ */
+#ifndef _ASM_RWSEM_H
+#define _ASM_RWSEM_H
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
+#endif
+
+#ifdef __KERNEL__
+
+#include <asm/compiler.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+struct rwsem_waiter;
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+ signed long count;
+#define RWSEM_UNLOCKED_VALUE 0x00000000L
+#define RWSEM_ACTIVE_BIAS 0x00000001L
+#define RWSEM_ACTIVE_MASK 0x0000ffffL
+#define RWSEM_WAITING_BIAS (-0x00010000L)
+#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+ spinlock_t wait_lock;
+ struct list_head wait_list;
+#if RWSEM_DEBUG
+ int debug;
+#endif
+};
+
+#if RWSEM_DEBUG
+#define __RWSEM_DEBUG_INIT , 0
+#else
+#define __RWSEM_DEBUG_INIT /* */
+#endif
+
+#define __RWSEM_INITIALIZER(name) \
+ { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
+ LIST_HEAD_INIT((name).wait_list) __RWSEM_DEBUG_INIT }
+
+#define DECLARE_RWSEM(name) \
+ struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+ sem->count = RWSEM_UNLOCKED_VALUE;
+ spin_lock_init(&sem->wait_lock);
+ INIT_LIST_HEAD(&sem->wait_list);
+#if RWSEM_DEBUG
+ sem->debug = 0;
+#endif
+}
+
+static inline void __down_read(struct rw_semaphore *sem)
+{
+ long oldcount;
+#ifndef CONFIG_SMP
+ oldcount = sem->count;
+ sem->count += RWSEM_ACTIVE_READ_BIAS;
+#else
+ long temp;
+ __asm__ __volatile__(
+ " .set noreorder\n"
+ "1: ll %0,%1\n"
+ " addiu %2,%0,%3\n"
+ " sc %2,%1\n"
+ " beq %2,0,1b\n"
+ " sync \n"
+ " .set reorder"
+ : "=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
+ : "I"(RWSEM_ACTIVE_READ_BIAS), "m" (sem->count)
+ : "memory");
+#endif
+ if (__builtin_expect(oldcount < 0, 0))
+ rwsem_down_read_failed(sem);
+}
+
+static inline void __down_write(struct rw_semaphore *sem)
+{
+ long oldcount;
+#ifndef CONFIG_SMP
+ oldcount = sem->count;
+ sem->count += RWSEM_ACTIVE_WRITE_BIAS;
+#else
+ long temp;
+ __asm__ __volatile__(
+ " .set noreorder\n"
+ "1: ll %0,%1\n"
+ " addu %2,%0,%3\n"
+ " sc %2,%1\n"
+ " beq %2,0,1b\n"
+ " sync \n"
+ " .set reorder"
+ : "=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
+ : "r" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count)
+ : "memory");
+#endif
+ if (__builtin_expect(oldcount, 0))
+ rwsem_down_write_failed(sem);
+}
+
+static inline void __up_read(struct rw_semaphore *sem)
+{
+ long oldcount;
+#ifndef CONFIG_SMP
+ oldcount = sem->count;
+ sem->count -= RWSEM_ACTIVE_READ_BIAS;
+#else
+ long temp;
+ __asm__ __volatile__(
+ " .set noreorder\n"
+ "1: ll %0,%1\n"
+ " addiu %2,%0,%3\n" /* no dsubiu */
+ " sc %2,%1\n"
+ " beq %2,0,1b\n"
+ " sync \n"
+ " .set reorder"
+ : "=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
+ : "I" (-RWSEM_ACTIVE_READ_BIAS), "m" (sem->count)
+ : "memory");
+#endif
+ if (__builtin_expect(oldcount < 0, 0))
+ if ((int)oldcount - RWSEM_ACTIVE_READ_BIAS == 0)
+ rwsem_wake(sem);
+}
+
+static inline void __up_write(struct rw_semaphore *sem)
+{
+ long count;
+#ifndef CONFIG_SMP
+ sem->count -= RWSEM_ACTIVE_WRITE_BIAS;
+ count = sem->count;
+#else
+ long temp;
+ __asm__ __volatile__(
+ " .set noreorder\n"
+ "1: ll %0,%1\n"
+ " subu %2,%0,%3\n"
+ " sc %2,%1\n"
+ " beq %2,0,1b\n"
+ " dsubu %0,%3,%0\n"
+ " sync \n"
+ " .set reorder"
+ : "=&r" (count), "=m" (sem->count), "=&r" (temp)
+ : "I" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count)
+ : "memory");
+#endif
+ if (__builtin_expect(count, 0))
+ if ((int)count == 0)
+ rwsem_wake(sem);
+}
+
+static inline void rwsem_atomic_add(long val, struct rw_semaphore *sem)
+{
+#ifndef CONFIG_SMP
+ sem->count += val;
+#else
+ long temp;
+ __asm__ __volatile__(
+ "1: ll %0,%1\n"
+ " addu %0,%2,%0\n"
+ " sc %0,%1\n"
+ " beq %0,0,1b\n"
+ " nop \n"
+ :"=&r" (temp), "=m" (sem->count)
+ :"r" (val), "m" (sem->count));
+#endif
+}
+
+static inline long rwsem_atomic_update(long val, struct rw_semaphore *sem)
+{
+#ifndef CONFIG_SMP
+ sem->count += val;
+ return sem->count;
+#else
+ long ret, temp;
+ __asm__ __volatile__(
+ "1: ll %0,%1\n"
+ " addu %2,%0,%3\n"
+ " sc %2,%1\n"
+ " beq %2,0,1b\n"
+ " addu %0,%3,%0\n"
+ :"=&r" (ret), "=m" (sem->count), "=&r" (temp)
+ :"Ir" (val), "m" (sem->count));
+
+ return ret;
+#endif
+}
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_RWSEM_H */
[-- Attachment #3: MIPS64 optimised rwsem patch --]
[-- Type: text/plain, Size: 5716 bytes --]
diff -uNr -x CVS -x TAGS linux-2.4-mips/arch/mips64/config.in linux-mips-rwsem/arch/mips64/config.in
--- linux-2.4-mips/arch/mips64/config.in Thu Jun 28 13:59:11 2001
+++ linux-mips-rwsem/arch/mips64/config.in Wed Jul 11 14:38:25 2001
@@ -27,8 +27,8 @@
fi
endmenu
-define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
-define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
#
# Select some configuration options automatically based on user selections
diff -uNr -x CVS -x TAGS linux-2.4-mips/include/asm-mips64/rwsem.h linux-mips-rwsem/include/asm-mips64/rwsem.h
--- linux-2.4-mips/include/asm-mips64/rwsem.h Thu Jan 1 01:00:00 1970
+++ linux-mips-rwsem/include/asm-mips64/rwsem.h Wed Jul 11 14:35:48 2001
@@ -0,0 +1,206 @@
+/* rwsem.h: R/W semaphores implemented using MIPS64 LLD/SCD
+ *
+ * Written by David Howells (dhowells@redhat.com).
+ *
+ * Derived from:
+ * - asm-i386/rwsem.h: written by David Howells (dhowells@redhat.com).
+ * - asm-alpha/rwsem.h: written by Ivan Kokshaysky <ink@jurassic.park.msu.ru>, 2001.
+ */
+#ifndef _ASM_RWSEM_H
+#define _ASM_RWSEM_H
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
+#endif
+
+#ifdef __KERNEL__
+
+#include <asm/compiler.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+struct rwsem_waiter;
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+ signed long count;
+#define RWSEM_UNLOCKED_VALUE 0x0000000000000000L
+#define RWSEM_ACTIVE_BIAS 0x0000000000000001L
+#define RWSEM_ACTIVE_MASK 0x00000000ffffffffL
+#define RWSEM_WAITING_BIAS (-0x0000000100000000L)
+#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+ spinlock_t wait_lock;
+ struct list_head wait_list;
+#if RWSEM_DEBUG
+ int debug;
+#endif
+};
+
+#if RWSEM_DEBUG
+#define __RWSEM_DEBUG_INIT , 0
+#else
+#define __RWSEM_DEBUG_INIT /* */
+#endif
+
+#define __RWSEM_INITIALIZER(name) \
+ { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
+ LIST_HEAD_INIT((name).wait_list) __RWSEM_DEBUG_INIT }
+
+#define DECLARE_RWSEM(name) \
+ struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+ sem->count = RWSEM_UNLOCKED_VALUE;
+ spin_lock_init(&sem->wait_lock);
+ INIT_LIST_HEAD(&sem->wait_list);
+#if RWSEM_DEBUG
+ sem->debug = 0;
+#endif
+}
+
+static inline void __down_read(struct rw_semaphore *sem)
+{
+ long oldcount;
+#ifndef CONFIG_SMP
+ oldcount = sem->count;
+ sem->count += RWSEM_ACTIVE_READ_BIAS;
+#else
+ long temp;
+ __asm__ __volatile__(
+ " .set noreorder\n"
+ "1: lld %0,%1\n"
+ " daddiu %2,%0,%3\n"
+ " scd %2,%1\n"
+ " beq %2,0,1b\n"
+ " sync \n"
+ " .set reorder"
+ : "=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
+ : "I"(RWSEM_ACTIVE_READ_BIAS), "m" (sem->count)
+ : "memory");
+#endif
+ if (__builtin_expect(oldcount < 0, 0))
+ rwsem_down_read_failed(sem);
+}
+
+static inline void __down_write(struct rw_semaphore *sem)
+{
+ long oldcount;
+#ifndef CONFIG_SMP
+ oldcount = sem->count;
+ sem->count += RWSEM_ACTIVE_WRITE_BIAS;
+#else
+ long temp;
+ __asm__ __volatile__(
+ " .set noreorder\n"
+ "1: lld %0,%1\n"
+ " daddu %2,%0,%3\n"
+ " scd %2,%1\n"
+ " beq %2,0,1b\n"
+ " sync \n"
+ " .set reorder"
+ : "=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
+ : "r" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count)
+ : "memory");
+#endif
+ if (__builtin_expect(oldcount, 0))
+ rwsem_down_write_failed(sem);
+}
+
+static inline void __up_read(struct rw_semaphore *sem)
+{
+ long oldcount;
+#ifndef CONFIG_SMP
+ oldcount = sem->count;
+ sem->count -= RWSEM_ACTIVE_READ_BIAS;
+#else
+ long temp;
+ __asm__ __volatile__(
+ " .set noreorder\n"
+ "1: lld %0,%1\n"
+ " daddiu %2,%0,%3\n" /* no dsubiu */
+ " scd %2,%1\n"
+ " beq %2,0,1b\n"
+ " sync \n"
+ " .set reorder"
+ : "=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
+ : "I" (-RWSEM_ACTIVE_READ_BIAS), "m" (sem->count)
+ : "memory");
+#endif
+ if (__builtin_expect(oldcount < 0, 0))
+ if ((int)oldcount - RWSEM_ACTIVE_READ_BIAS == 0)
+ rwsem_wake(sem);
+}
+
+static inline void __up_write(struct rw_semaphore *sem)
+{
+ long count;
+#ifndef CONFIG_SMP
+ sem->count -= RWSEM_ACTIVE_WRITE_BIAS;
+ count = sem->count;
+#else
+ long temp;
+ __asm__ __volatile__(
+ " .set noreorder\n"
+ "1: lld %0,%1\n"
+ " dsubu %2,%0,%3\n"
+ " scd %2,%1\n"
+ " beq %2,0,1b\n"
+ " dsubu %0,%3,%0\n"
+ " sync \n"
+ " .set reorder"
+ : "=&r" (count), "=m" (sem->count), "=&r" (temp)
+ : "I" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count)
+ : "memory");
+#endif
+ if (__builtin_expect(count, 0))
+ if ((int)count == 0)
+ rwsem_wake(sem);
+}
+
+static inline void rwsem_atomic_add(long val, struct rw_semaphore *sem)
+{
+#ifndef CONFIG_SMP
+ sem->count += val;
+#else
+ long temp;
+ __asm__ __volatile__(
+ "1: lld %0,%1\n"
+ " daddu %0,%2,%0\n"
+ " scd %0,%1\n"
+ " beq %0,0,1b\n"
+ " nop \n"
+ :"=&r" (temp), "=m" (sem->count)
+ :"r" (val), "m" (sem->count));
+#endif
+}
+
+static inline long rwsem_atomic_update(long val, struct rw_semaphore *sem)
+{
+#ifndef CONFIG_SMP
+ sem->count += val;
+ return sem->count;
+#else
+ long ret, temp;
+ __asm__ __volatile__(
+ "1: lld %0,%1\n"
+ " daddu %2,%0,%3\n"
+ " scd %2,%1\n"
+ " beq %2,0,1b\n"
+ " daddu %0,%3,%0\n"
+ :"=&r" (ret), "=m" (sem->count), "=&r" (temp)
+ :"Ir" (val), "m" (sem->count));
+
+ return ret;
+#endif
+}
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_RWSEM_H */
[-- Attachment #4: 64-bit rwsem fix for older kernels --]
[-- Type: text/plain, Size: 469 bytes --]
diff -uNr -x CVS -x TAGS linux-2.4-mips/lib/rwsem.c linux-mips-rwsem/lib/rwsem.c
--- linux-2.4-mips/lib/rwsem.c Mon Apr 30 09:55:41 2001
+++ linux-mips-rwsem/lib/rwsem.c Wed Jul 11 14:04:02 2001
@@ -112,7 +112,7 @@
*/
static inline struct rw_semaphore *rwsem_down_failed_common(struct rw_semaphore *sem,
struct rwsem_waiter *waiter,
- __s32 adjustment)
+ signed long adjustment)
{
struct task_struct *tsk = current;
signed long count;
next reply other threads:[~2001-07-11 14:01 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-07-11 14:00 David Howells [this message]
2001-07-11 14:18 ` optimised rw-semaphores for MIPS/MIPS64 David Howells
2001-07-11 16:41 ` Andrea Arcangeli
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2508.994860047@warthog.cambridge.redhat.com \
--to=dhowells@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@fnet.fr \
--cc=ralf@gnu.ai.mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.