curcpu()の仕様を変えたい in OpenBSD/sgi

OpenBSDでカレントプロセッサのcpu_info(※per-CPUなデータを保存する構造体)のポインタを取得するにはcurcpu()というマクロを呼ぶのだが、現状のOpenBSD/sgiではこんな風になっている:

#define curcpu() cpu_info[cpu_number()]

で、cpu_number()はハードウェアレジスタを読んでCPUの物理IDを取得している。
が、先日書いたようにOrigin 350においては物理IDとautoconfで割り当てるIDを分けたい。

また、curcpu()の度に毎回物理IDをロードして配列からポインタを取り出すのはあまり速くはない。
出来ればあるレジスタにポインタが入ってて、取り出すだけで使えるというような状態だと嬉しい。
ここで、CP0のLLAddrレジスタが未使用で使えるという話が以前からあった。
しかし、32bit幅なので64bitポインタをツッコむにはちょっと工夫が必要。でも不可能じゃない。

この二点を一度に解決するパッチを書いた。

Index: mips64/include/asm.h
===================================================================
RCS file: /cvs/src/sys/arch/mips64/include/asm.h,v
retrieving revision 1.10
diff -u -p -r1.10 asm.h
--- mips64/include/asm.h	9 Jan 2010 23:34:29 -0000	1.10
+++ mips64/include/asm.h	25 Apr 2010 20:53:02 -0000
@@ -299,11 +299,9 @@ x: ;				\
 
 #ifdef MULTIPROCESSOR
 #define GET_CPU_INFO(ci, tmp)		\
-	HW_CPU_NUMBER(tmp);		\
-	PTR_SLL	 tmp, tmp, LOGREGSZ;	\
-	LA	 ci, cpu_info;		\
-	PTR_ADDU ci, ci, tmp;		\
-	PTR_L	 ci, 0(ci)
+	LOAD_XKPHYS(ci, CCA_CACHED);	\
+	mfc0	tmp, COP_0_LLADDR;	\
+	or	ci, ci, tmp
 #else  /* MULTIPROCESSOR */
 #define GET_CPU_INFO(ci, tmp)		\
 	LA	ci, cpu_info_primary

curcpu()のアセンブリ版マクロ。
ここで、配列からポインタを取り出す代わりにLLADDRからポインタを取り出し64bitアドレスを復元。

Index: mips64/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/mips64/include/cpu.h,v
retrieving revision 1.57
diff -u -p -r1.57 cpu.h
--- mips64/include/cpu.h	28 Feb 2010 18:01:36 -0000	1.57
+++ mips64/include/cpu.h	25 Apr 2010 20:53:02 -0000
@@ -428,18 +428,22 @@ extern struct cpu_info *cpu_info_list;
 
 #ifdef MULTIPROCESSOR
 #define MAXCPUS				4
-#define curcpu()			(cpu_info[cpu_number()])
+extern struct cpu_info *getcurcpu(void);
+extern void setcurcpu(struct cpu_info *);
+#ifdef DEBUG
+extern struct cpu_info *get_cpu_info(int);
+#endif
+#define curcpu() getcurcpu()
 #define	CPU_IS_PRIMARY(ci)		((ci)->ci_flags & CPUF_PRIMARY)
-#define cpu_number()			hw_cpu_number()
+#define cpu_number()			(curcpu()->ci_cpuid)
 
 extern struct cpuset cpus_running;
-extern struct cpu_info *cpu_info[];
 void cpu_unidle(struct cpu_info *);
 void cpu_boot_secondary_processors(void);
 #define cpu_boot_secondary(ci)          hw_cpu_boot_secondary(ci)
 #define cpu_hatch(ci)                   hw_cpu_hatch(ci)
 
-vaddr_t smp_malloc(size_t);
+vaddr_t alloc_contiguous_pages(size_t);
 
 #define MIPS64_IPI_NOP		0x00000001
 #define MIPS64_IPI_RENDEZVOUS	0x00000002

cpu_info[]配列を削除。代わりにlladdrへアクセスするgetcurcpu(), setcurcpu(ci)を追加。
curcpu()はgetcurcpu()を呼ぶだけ。

Index: mips64/mips64/context.S
===================================================================
RCS file: /cvs/src/sys/arch/mips64/mips64/context.S,v
retrieving revision 1.44
diff -u -p -r1.44 context.S
--- mips64/mips64/context.S	13 Feb 2010 14:04:45 -0000	1.44
+++ mips64/mips64/context.S	25 Apr 2010 20:53:03 -0000
@@ -145,7 +145,8 @@ NON_LEAF(cpu_switchto_asm, FRAMESZ(CF_SZ
 	PTR_L	t0, P_VMSPACE(s0)		# p->p_vmspace
 	PTR_L	t1, VMSPACE_PMAP(t0)		# ->vm_map.pmap
 #ifdef MULTIPROCESSOR
-	HW_CPU_NUMBER(v0)			# cpuid
+	GET_CPU_INFO(v0, t2)
+	PTR_L	v0, CI_CPUID(v0)
 	PTR_SLL	v0, v0, 0x3			# size of pmap_asid_info
 	PTR_ADDU t1, t1, v0
 #endif

物理IDをコードから排除。全てautoconfの番号へ。

Index: mips64/mips64/cp0access.S
===================================================================
RCS file: /cvs/src/sys/arch/mips64/mips64/cp0access.S,v
retrieving revision 1.12
diff -u -p -r1.12 cp0access.S
--- mips64/mips64/cp0access.S	9 Jan 2010 23:34:29 -0000	1.12
+++ mips64/mips64/cp0access.S	25 Apr 2010 20:53:03 -0000
@@ -192,3 +192,17 @@ LEAF(cp0_setperfctrl, 0)
 	j	ra
 	nop
 END(cp0_setperfctrl)
+
+#ifdef MULTIPROCESSOR
+LEAF(getcurcpu, 0)
+	GET_CPU_INFO(v0, v1)
+	jr	ra
+END(getcurcpu)
+
+LEAF(setcurcpu, 0)
+	mtc0	a0, COP_0_LLADDR
+	nop; nop
+	j	ra
+	nop
+END(setcurcpu)
+#endif

getcurcpu(), setcurcpu()の実体。
単にLLADDRへアクセスするだけ。

Index: mips64/mips64/cpu.c
===================================================================
RCS file: /cvs/src/sys/arch/mips64/mips64/cpu.c,v
retrieving revision 1.28
diff -u -p -r1.28 cpu.c
--- mips64/mips64/cpu.c	28 Mar 2010 17:09:36 -0000	1.28
+++ mips64/mips64/cpu.c	25 Apr 2010 20:53:03 -0000
@@ -41,15 +41,9 @@ void	cpuattach(struct device *, struct d
 
 struct cpu_info cpu_info_primary;
 struct cpu_info *cpu_info_list = &cpu_info_primary;
+struct cpu_info *cpu_info_secondaries;
 #ifdef MULTIPROCESSOR
 struct cpuset cpus_running;
-
-/*
- * Array of CPU info structures.  Must be statically-allocated because
- * curproc, etc. are used early.
- */
-
-struct cpu_info *cpu_info[MAXCPUS] = { &cpu_info_primary };
 #endif
 
 vaddr_t	CpuCacheAliasMask;
@@ -91,18 +85,19 @@ cpuattach(struct device *parent, struct 
 #ifdef MULTIPROCESSOR
 		ci->ci_flags |= CPUF_RUNNING | CPUF_PRESENT | CPUF_PRIMARY;
 		cpuset_add(&cpus_running, ci);
+		cpu_info_secondaries = (struct cpu_info *)alloc_contiguous_pages(
+			sizeof(struct cpu_info) * ncpusfound - 1);
+		if (cpu_info_secondaries == NULL)
+			panic("unable to allocate cpu_info\n");
+		bzero((char *)cpu_info_secondaries, sizeof(struct cpu_info) * ncpusfound - 1);
 #endif
 	}
 #ifdef MULTIPROCESSOR
 	else {
-		ci = (struct cpu_info *)smp_malloc(sizeof(*ci));
-		if (ci == NULL)
-			panic("unable to allocate cpu_info\n");
-		bzero((char *)ci, sizeof(*ci));
+		ci = &cpu_info_secondaries[cpuno - 1];
 		ci->ci_next = cpu_info_list->ci_next;
 		cpu_info_list->ci_next = ci;
 		ci->ci_flags |= CPUF_PRESENT;
-		cpu_info[cpuno] = ci;
 	}
 #endif
 	ci->ci_self = ci;
@@ -373,16 +368,28 @@ save_fpu(void)
 }
 
 #ifdef MULTIPROCESSOR
+#ifdef DEBUG
+struct cpu_info *
+get_cpu_info(int cpuno)
+{
+	struct cpu_info *ci;
+	CPU_INFO_ITERATOR cii;
+
+	CPU_INFO_FOREACH(cii, ci) {
+		if (ci->ci_cpuid == cpuno)
+			return ci;
+	}
+	return NULL;
+}
+#endif
+
 void
 cpu_boot_secondary_processors(void)
 {
        struct cpu_info *ci;
-       u_long i;
+	CPU_INFO_ITERATOR cii;
 
-       for (i = 0; i < MAXCPUS; i++) {
-               ci = cpu_info[i];
-               if (ci == NULL)
-                       continue;
+	CPU_INFO_FOREACH(cii, ci) {
                if ((ci->ci_flags & CPUF_PRESENT) == 0)
                        continue;
                if (ci->ci_flags & CPUF_PRIMARY)
@@ -391,7 +398,7 @@ cpu_boot_secondary_processors(void)
                sched_init_cpu(ci);
                ci->ci_randseed = random();
                cpu_boot_secondary(ci);
-       }
+	}
 
        /* This must called after xheart0 has initialized, so here is 
 	* the best place to do so.
@@ -407,31 +414,21 @@ cpu_unidle(struct cpu_info *ci)
 }
 
 vaddr_t 
-smp_malloc(size_t size)
+alloc_contiguous_pages(size_t size)
 {
-       struct pglist mlist;
-       struct vm_page *m;
-       int error;
-       vaddr_t va;
-       paddr_t pa;
-
-       if (size < PAGE_SIZE) {
-	       va = (vaddr_t)malloc(size, M_DEVBUF, M_NOWAIT);
-	       if (va == NULL)
-		       return NULL;
-	       error = pmap_extract(pmap_kernel(), va, &pa);
-	       if (error == FALSE)
-		       return NULL;
-       } else { 
-	       TAILQ_INIT(&mlist);
-	       error = uvm_pglistalloc(size, 0, -1L, 0, 0,
-		   &mlist, 1, UVM_PLA_NOWAIT);
-	       if (error)
-		       return NULL;
-	       m = TAILQ_FIRST(&mlist);
-	       pa = VM_PAGE_TO_PHYS(m);
-       }
+	struct pglist mlist;
+	struct vm_page *m;
+	int error;
+	paddr_t pa;
+
+	TAILQ_INIT(&mlist);
+	error = uvm_pglistalloc(size, 0, -1, 0, 0,
+		&mlist, 1, UVM_PLA_NOWAIT);
+	if (error)
+		return NULL;
+	m = TAILQ_FIRST(&mlist);
+	pa = VM_PAGE_TO_PHYS(m);
 
-       return PHYS_TO_XKPHYS(pa, CCA_CACHED);
+	return PHYS_TO_XKPHYS(pa, CCA_CACHED);
 }
 #endif

複数の問題を一度に片付けていて少々ややこしくなっている。
まず、cpu_info[]をやめた。
lladdrが32bit幅な関係上、smp_malloc()内でアロケート出来るのは32bit空間で表現出来るアドレスまでなので、位置が指定できないmalloc()をやめてuvm_pglistalloc()だけにする。
ページ単位でアロケートしなければならなくなったので、毎度呼ぶのをやめて一括でcpu_info_secondariesへアロケートすることに。
なので関数名もalloc_contiguous_pages()へ変えてみた。

Index: mips64/mips64/genassym.cf
===================================================================
RCS file: /cvs/src/sys/arch/mips64/mips64/genassym.cf,v
retrieving revision 1.6
diff -u -p -r1.6 genassym.cf
--- mips64/mips64/genassym.cf	9 Jan 2010 23:43:43 -0000	1.6
+++ mips64/mips64/genassym.cf	25 Apr 2010 20:53:03 -0000
@@ -58,6 +58,7 @@ member	pcb_onfault
 member	pcb_segtab
 
 struct	cpu_info
+member	ci_cpuid
 member	ci_curproc
 member	ci_curprocpaddr
 member	ci_fpuproc

CI_CPUIDマクロの生成。

Index: mips64/mips64/ipifuncs.c
===================================================================
RCS file: /cvs/src/sys/arch/mips64/mips64/ipifuncs.c,v
retrieving revision 1.3
diff -u -p -r1.3 ipifuncs.c
--- mips64/mips64/ipifuncs.c	21 Apr 2010 14:57:11 -0000	1.3
+++ mips64/mips64/ipifuncs.c	25 Apr 2010 20:53:03 -0000
@@ -119,10 +119,10 @@ mips64_ipi_intr(void *arg)
 void
 mips64_send_ipi(unsigned int cpuid, unsigned int ipimask)
 {
-#ifdef DIAGNOSTIC
-	if (cpuid >= CPU_MAXID || cpu_info[cpuid] == NULL)
+#ifdef DEBUG
+	if (cpuid >= CPU_MAXID || get_cpu_info(cpuid) == NULL)
 		panic("mips_send_ipi: bogus cpu_id");
-	if (!cpuset_isset(&cpus_running, cpu_info[cpuid]))
+	if (!cpuset_isset(&cpus_running, get_cpu_info(cpuid)))
 	        panic("mips_send_ipi: CPU %ld not running", cpuid);
 #endif

cpu_info[]の排除。
代わりにcpu.cへget_cpu_info()を用意した。

Index: sgi/include/asm.h
===================================================================
RCS file: /cvs/src/sys/arch/sgi/include/asm.h,v
retrieving revision 1.2
diff -u -p -r1.2 asm.h
--- sgi/include/asm.h	30 Sep 2009 06:22:00 -0000	1.2
+++ sgi/include/asm.h	25 Apr 2010 20:53:03 -0000
@@ -2,13 +2,4 @@
 
 /* Use Mips generic include file */
 
-#ifdef MULTIPROCESSOR
-#define HW_CPU_NUMBER(reg)			\
-	LA reg, HW_CPU_NUMBER_REG;		\
-	PTR_L reg, 0(reg)
-#else  /* MULTIPROCESSOR */
-#define HW_CPU_NUMBER(reg)			\
-	LI reg, 0
-#endif /* MULTIPROCESSOR */
-
 #include <mips64/asm.h>

物理IDの排除。

Index: sgi/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/sgi/include/cpu.h,v
retrieving revision 1.8
diff -u -p -r1.8 cpu.h
--- sgi/include/cpu.h	9 Jan 2010 23:34:29 -0000	1.8
+++ sgi/include/cpu.h	25 Apr 2010 20:53:03 -0000
@@ -45,16 +45,7 @@
 #define _SGI_CPU_H_
 
 #ifdef _KERNEL
-
-#ifdef MULTIPROCESSOR
-
-#if defined(TGT_OCTANE)
-#define HW_CPU_NUMBER_REG 0x900000000ff50000 /* HEART_PRID */
-#else
-#error MULTIPROCESSOR kernel not supported on this configuration
-#endif
-
-#if !defined(_LOCORE)
+#if defined(MULTIPROCESSOR) && !defined(_LOCORE)
 struct cpu_info;
 void hw_cpu_boot_secondary(struct cpu_info *);
 void hw_cpu_hatch(struct cpu_info *);
@@ -62,15 +53,7 @@ void hw_cpu_spinup_trampoline(struct cpu
 int  hw_ipi_intr_establish(int (*)(void *), u_long);
 void hw_ipi_intr_set(u_long);
 void hw_ipi_intr_clear(u_long);
-#endif
-
-#define hw_cpu_number() (*(uint64_t *)HW_CPU_NUMBER_REG)
-
-#else	/* MULTIPROCESSOR */
-
-#define hw_cpu_number() 0
-
-#endif	/* MULTIPROCESSOR */
+#endif	/* MULTIPROCESSOR && !_LOCORE */
 
 /*
  * Define soft selected cache functions.

物理IDの排除。

Index: sgi/sgi/ip30_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/sgi/sgi/ip30_machdep.c,v
retrieving revision 1.41
diff -u -p -r1.41 ip30_machdep.c
--- sgi/sgi/ip30_machdep.c	21 Apr 2010 14:57:11 -0000	1.41
+++ sgi/sgi/ip30_machdep.c	25 Apr 2010 20:53:03 -0000
@@ -531,7 +531,7 @@ hw_cpu_boot_secondary(struct cpu_info *c
 	    scachesz, fanloads, launch, rndvz,
 	    stackaddr, lparam, rparam, idleflag);
 #endif
-	kstack = smp_malloc(USPACE);
+	kstack = alloc_contiguous_pages(USPACE);
 	if (kstack == NULL)
 		panic("unable to allocate idle stack\n");
 	bzero((char *)kstack, USPACE);
@@ -552,6 +552,11 @@ void
 hw_cpu_hatch(struct cpu_info *ci)
 {
 	int s;
+
+	/*
+	 * Set curcpu address on this processor.
+	 */
+	setcurcpu(ci);
 
 	/*
 	 * Make sure we can access the extended address space.

smp_malloc()の名称変更、あと重要なlladdrへのcurcpuのセット。

Index: sgi/sgi/ip30_nmi.S
===================================================================
RCS file: /cvs/src/sys/arch/sgi/sgi/ip30_nmi.S,v
retrieving revision 1.2
diff -u -p -r1.2 ip30_nmi.S
--- sgi/sgi/ip30_nmi.S	13 Jan 2010 23:24:27 -0000	1.2
+++ sgi/sgi/ip30_nmi.S	25 Apr 2010 20:53:03 -0000
@@ -23,9 +23,7 @@
 
 #include <arch/sgi/sgi/ip30.h>
 
-#ifndef MULTIPROCESSOR
 #define	HW_CPU_NUMBER_REG	0x900000000ff50000	/* HEART_PRID */
-#endif
 
 #include "assym.h"

つじつま合わせ。

Index: sgi/sgi/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/sgi/sgi/machdep.c,v
retrieving revision 1.100
diff -u -p -r1.100 machdep.c
--- sgi/sgi/machdep.c	3 Mar 2010 12:25:09 -0000	1.100
+++ sgi/sgi/machdep.c	25 Apr 2010 20:53:04 -0000
@@ -150,6 +150,11 @@ mips_init(int argc, void *argv, caddr_t 
 	extern char *hw_vendor;
 
 	/*
+	 * Set curcpu address on primary processor.
+	 */
+	setcurcpu(&cpu_info_primary);
+
+	/*
 	 * Make sure we can access the extended address space.
 	 * Note that r10k and later do not allow XUSEG accesses
 	 * from kernel mode unless SR_UX is set.

こちらも重要なlladdrへのセット。