shithub: riscv

Download patch

ref: b0d226705cec8f36339adce5d95b4feda1deba02
parent: 17f0b2ce38f3c845a3bbbe0630185ca8dac684a4
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Nov 7 11:48:14 EST 2018

bcm: speed up co-processor operations by avoiding i+d cache flush on each operation

coproc.c generated the instrucitons anew each time,
requiering a i+d cache flush for each operation.

instead, we can speed this up like this:

given that the coprocessor registers are per cpu, we can
assume that interrupts have already been disabled by
the caller to prevent a process switch to another cpu.

we cache the instructions generated in a static append
only buffer and maintain separate end pointers for each
cpu.

the cache flushes only need to be done when new
operations have been added to the buffer.

--- a/sys/src/9/bcm/coproc.c
+++ b/sys/src/9/bcm/coproc.c
@@ -1,1 +1,163 @@
-#include "../teg2/coproc.c"
+/*
+ * arm co-processors
+ * mainly to cope with arm hard-wiring register numbers into instructions.
+ *
+ * CP15 (system control) is the one that gets used the most in practice.
+ *
+ * these routines must be callable from KZERO.
+ *
+ * on a multiprocessor, process switching to another cpu is assumed
+ * to be inhibited by the caller as these registers are local to the cpu.
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "arm.h"
+
+enum {
+	/* alternates:	0xe12fff1e	BX (R14); last e is R14 */
+	/*		0xe28ef000	B 0(R14); second e is R14 (ken) */
+	Retinst	= 0xe1a0f00e,		/* MOV R14, R15 */
+
+	Opmask	= MASK(3),
+	Regmask	= MASK(4),
+};
+
+static void*
+mkinstr(ulong wd)
+{
+	static ulong ib[256], *ep[MAXMACH+1];
+	static Lock lk;
+	ulong *ip, *ie;
+
+	ie = ep[m->machno];
+	for(ip = ib; ip < ie; ip += 2)
+		if(*ip == wd)
+			return ip;
+
+	ilock(&lk);
+	ie = ep[MAXMACH];
+	for(; ip < ie; ip += 2)
+		if(*ip == wd)
+			goto Found;
+	if(ip >= &ib[nelem(ib)])
+		panic("mkinstr: out of instrucuction buffer");
+	ip[0] = wd;
+	ip[1] = Retinst;
+	ep[MAXMACH] = ie = ip + 2;
+	cachedwbse(ip, 2*sizeof(*ip));
+Found:
+	iunlock(&lk);
+	cacheiinv();
+	ep[m->machno] = ie;
+	return ip;
+}
+
+
+static void*
+setupcpop(ulong opcode, int cp, int op1, int crn, int crm,
+	int op2)
+{
+	op1 &= Opmask;
+	op2 &= Opmask;
+	crn &= Regmask;
+	crm &= Regmask;
+	cp  &= Regmask;
+	return mkinstr(opcode | op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm);
+}
+
+ulong
+cprd(int cp, int op1, int crn, int crm, int op2)
+{
+	/*
+	 * MRC.  return value will be in R0, which is convenient.
+	 * Rt will be R0.
+	 */
+	ulong (*fp)(void) = setupcpop(0xee100010, cp, op1, crn, crm, op2);
+	return fp();
+}
+
+void
+cpwr(int cp, int op1, int crn, int crm, int op2, ulong val)
+{
+	/* MCR, Rt is R0 */
+	void (*fp)(ulong) = setupcpop(0xee000010, cp, op1, crn, crm, op2);
+	fp(val);
+}
+
+ulong
+cprdsc(int op1, int crn, int crm, int op2)
+{
+	return cprd(CpSC, op1, crn, crm, op2);
+}
+
+void
+cpwrsc(int op1, int crn, int crm, int op2, ulong val)
+{
+	cpwr(CpSC, op1, crn, crm, op2, val);
+}
+
+/* floating point */
+
+/* fp coproc control */
+static void*
+setupfpctlop(int opcode, int fpctlreg)
+{
+	fpctlreg &= Nfpctlregs - 1;
+	return mkinstr(opcode | fpctlreg << 16 | 0 << 12 | CpFP << 8);
+}
+
+ulong
+fprd(int fpreg)
+{
+	/*
+	 * VMRS.  return value will be in R0, which is convenient.
+	 * Rt will be R0.
+	 */
+	ulong (*fp)(void) = setupfpctlop(0xeef00010, fpreg);
+	return fp();
+}
+
+void
+fpwr(int fpreg, ulong val)
+{
+	/*
+	 * fpu might be off and this VMSR might enable it
+	 * VMSR, Rt is R0
+	 */
+	void (*fp)(ulong) = setupfpctlop(0xeee00010, fpreg);
+	fp(val);
+}
+
+/* fp register access; don't bother with single precision */
+static void*
+setupfpop(int opcode, int fpreg)
+{
+	ulong wd = opcode | 0 << 16 | (fpreg & (16 - 1)) << 12;
+	if (fpreg >= 16)
+		wd |= 1 << 22;		/* high bit of dfp reg # */
+	return mkinstr(wd);
+}
+
+ulong
+fpsavereg(int fpreg, uvlong *fpp)
+{
+	/*
+	 * VSTR.  pointer will be in R0, which is convenient.
+	 * Rt will be R0.
+	 */
+	ulong (*fp)(uvlong *) = setupfpop(0xed000000 | CpDFP << 8, fpreg);
+	return fp(fpp);
+}
+
+void
+fprestreg(int fpreg, uvlong val)
+{
+	/* VLDR, Rt is R0 */
+	void (*fp)(uvlong *) = setupfpop(0xed100000 | CpDFP << 8, fpreg);
+	fp(&val);
+}
--- a/sys/src/9/bcm/vfp3.c
+++ b/sys/src/9/bcm/vfp3.c
@@ -338,8 +338,12 @@
 void
 fpusysprocsetup(Proc *p)
 {
+	int s;
+
+	s = splhi();
 	p->fpstate = FPinit;
 	fpoff();
+	splx(s);
 }
 
 static void