code: plan9front

Download patch

ref: 65061470665b3f91f01d23bad6a54704e8aa5851
parent: 5458506881d9ff73287df354d3be75b35d339f24
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Jul 7 15:24:10 EDT 2015

libc/arm: implement _tas() with LDREX/STREX, execute memory barrier on smp systems (zynq)

--- a/sys/src/libc/arm/atom.s
+++ b/sys/src/libc/arm/atom.s
@@ -1,58 +1,50 @@
-#define	CLREX		WORD	$0xf57ff01f
-#define	LDREX(a,r)	WORD	$(0xe<<28|0x01900f9f | (a)<<16 | (r)<<12)
-/* `The order of operands is from left to right in dataflow order' - asm man */
-#define	STREX(v,a,r)	WORD	$(0xe<<28|0x01800f90 | (a)<<16 | (r)<<12 | (v)<<0)
-
 /*
- * int cas(ulong *p, ulong ov, ulong nv);
+ * int cas32(u32int *p, u32int ov, u32int nv);
+ * int cas(uint *p, int ov, int nv);
+ * int casp(void **p, void *ov, void *nv);
+ * int casl(ulong *p, ulong ov, ulong nv);
  */
-
-TEXT	cas+0(SB),0,$0		/* r0 holds p */
-TEXT	casp+0(SB),0,$0		/* r0 holds p */
+TEXT cas32(SB), 1, $-4
+TEXT cas(SB), 1, $-4
+TEXT casp(SB), 1, $-4
+TEXT casl(SB), 1, $-4
 	MOVW	ov+4(FP), R1
 	MOVW	nv+8(FP), R2
 spincas:
-	LDREX(0,3)	/*	LDREX	0(R0),R3	*/
+	LDREX	(R0), R3
 	CMP.S	R3, R1
 	BNE	fail
-	STREX(2,0,4)	/*	STREX	0(R0),R2,R4	*/
+	STREX	R2, (R0), R4
 	CMP.S	$0, R4
 	BNE	spincas
 	MOVW	$1, R0
-	RET
+	MOVW	_barrier(SB), R5
+	B	(R5)
 fail:
 	CLREX
 	MOVW	$0, R0
 	RET
 
-TEXT _xinc(SB), $0	/* void	_xinc(long *); */
-TEXT ainc(SB), $0	/* long ainc(long *); */
+TEXT _xinc(SB), 1, $-4	/* void	_xinc(long *); */
+TEXT ainc(SB), 1, $-4	/* long ainc(long *); */
 spinainc:
-	LDREX(0,3)	/*	LDREX	0(R0),R3	*/
+	LDREX	(R0), R3
 	ADD	$1,R3
-	STREX(3,0,4)	/*	STREX	0(R0),R3,R4	*/
+	STREX	R3, (R0), R4
 	CMP.S	$0, R4
 	BNE	spinainc
 	MOVW	R3, R0
-	RET
+	MOVW	_barrier(SB), R5
+	B	(R5)
 
-TEXT _xdec(SB), $0	/* long _xdec(long *); */
-TEXT adec(SB), $0	/* long adec(long *); */
+TEXT _xdec(SB), 1, $-4	/* long _xdec(long *); */
+TEXT adec(SB), 1, $-4	/* long adec(long *); */
 spinadec:
-	LDREX(0,3)	/*	LDREX	0(R0),R3	*/
+	LDREX	(R0), R3
 	SUB	$1,R3
-	STREX(3,0,4)	/*	STREX	0(R0),R3,R4	*/
+	STREX	R3, (R0), R4
 	CMP.S	$0, R4
 	BNE	spinadec
 	MOVW	R3, R0
-	RET
-
-TEXT loadlinked(SB), $0	/* long loadlinked(long *); */
-	LDREX(0,0)	/*	LDREX	0(R0),R0	*/
-	RET
-
-TEXT storecond(SB), $0	/* int storecond(long *, long); */
-	MOVW	ov+4(FP), R3
-	STREX(3,0,0)	/*	STREX	0(R0),R3,R0	*/
-	RSB	$1, R0
-	RET
+	MOVW	_barrier(SB), R5
+	B	(R5)
--- a/sys/src/libc/arm/cas.s
+++ /dev/null
@@ -1,28 +1,0 @@
-
-/*
- * int swp(int r, int *p);
- * uchar swpb(uchar r, uchar *p);
- *
- * int cas(uintptr *p, uintptr ov, uintptr nv);
- */
-
-#define	LDREX(a,r)	WORD	$(0xe<<28|0x01900f9f | (a)<<16 | (r)<<12)
-#define	STREX(a,v,r)	WORD	$(0xe<<28|0x01800f90 | (a)<<16 | (r)<<12 | (v)<<0)
-
-TEXT	cas+0(SB),0,$12		/* r0 holds p */
-	MOVW	ov+4(FP), R1
-	MOVW	nv+8(FP), R2
-spin:
-/*	LDREX	0(R0),R3	*/
-	LDREX(0,3)
-	CMP.S	R3, R1
-	BNE	fail
-/*	STREX	0(R0),R2,R4	*/
-	STREX(0,2,4)
-	CMP.S	$0, R4
-	BNE	spin
-	MOVW	$1, R0
-	RET
-fail:
-	MOVW	$0, R0
-	RET
--- /dev/null
+++ b/sys/src/libc/arm/lock.c
@@ -1,0 +1,89 @@
+#include <u.h>
+#include <libc.h>
+
+static long lockinit(long);
+
+/*
+ * barrier is called from atom.s and tas.s assembly
+ * to execute memory barrier.
+ */
+long (*_barrier)(long) = lockinit;
+
+static int
+cpus(void)
+{
+	char buf[256], *p;
+	int f, n;
+
+	f = open("#c/sysstat", OREAD);
+	if(f < 0)
+		return -1;
+	n = read(f, buf, sizeof(buf)-1);
+	close(f);
+	if(n <= 0)
+		return -1;
+	buf[n] = '\0';
+	n = 0;
+	p = buf;
+	while(*p != '\0'){
+		if(*p == '\n')
+			n++;
+		p++;
+	}
+	return n;
+}
+
+long _dmb(long);
+
+static long
+_nop(long r0)
+{
+	return r0;
+}
+
+static long
+lockinit(long r0)
+{
+	if(cpus() > 1)
+		_barrier = _dmb;
+	else
+		_barrier = _nop;
+	return (*_barrier)(r0);
+}
+
+void
+lock(Lock *lk)
+{
+	int i;
+
+	/* once fast */
+	if(!_tas(&lk->val))
+		return;
+	/* a thousand times pretty fast */
+	for(i=0; i<1000; i++){
+		if(!_tas(&lk->val))
+			return;
+		sleep(0);
+	}
+	/* now nice and slow */
+	for(i=0; i<1000; i++){
+		if(!_tas(&lk->val))
+			return;
+		sleep(100);
+	}
+	/* take your time */
+	while(_tas(&lk->val))
+		sleep(1000);
+}
+
+int
+canlock(Lock *lk)
+{
+	return _tas(&lk->val) == 0;
+}
+
+void
+unlock(Lock *lk)
+{
+	lk->val = (*_barrier)(0);
+}
--- a/sys/src/libc/arm/mkfile
+++ b/sys/src/libc/arm/mkfile
@@ -23,6 +23,7 @@
 	cycles.c\
 	notejmp.c\
 	vlrt.c\
+	lock.c\
 
 HFILES=/sys/include/libc.h
 
--- a/sys/src/libc/arm/tas.s
+++ b/sys/src/libc/arm/tas.s
@@ -1,5 +1,14 @@
-TEXT	_tas(SB), 1, $-4
-	MOVW	R0,R1
-	MOVW	$1,R0
-	SWPW	R0,(R1)		/* fix: deprecated in armv7 */
+TEXT _tas(SB), 1, $-4
+	MOVW	$1, R2
+_tas1:
+	LDREX	(R0), R1
+	STREX	R2, (R0), R3
+	CMP.S	$0, R3
+	BNE	_tas1
+	MOVW	R1, R0
+	MOVW	_barrier(SB), R4
+	B	(R4)
+
+TEXT _dmb(SB), 1, $-4
+	WORD $0xf57ff05f
 	RET