Module Name:    src
Committed By:   rmind
Date:           Tue Jun 22 18:29:03 UTC 2010

Modified Files:
        src/sys/arch/alpha/alpha: ipifuncs.c
        src/sys/arch/alpha/include: intr.h
        src/sys/arch/powerpc/pic: ipi.c ipivar.h
        src/sys/arch/sparc/sparc: cpu.c
        src/sys/arch/sparc64/sparc64: ipifuncs.c
        src/sys/arch/vax/include: cpu.h
        src/sys/arch/vax/vax: multicpu.c
        src/sys/arch/x86/include: intrdefs.h
        src/sys/arch/x86/x86: ipi.c
        src/sys/kern: subr_xcall.c
        src/sys/sys: xcall.h

Log Message:
Implement high priority (XC_HIGHPRI) xcall(9) mechanism - a facility
to execute functions from software interrupt context, at SOFTINT_CLOCK.
Functions must be lightweight.  Will be used for passive serialization.

OK a...@.


To generate a diff of this commit:
cvs rdiff -u -r1.41 -r1.42 src/sys/arch/alpha/alpha/ipifuncs.c
cvs rdiff -u -r1.67 -r1.68 src/sys/arch/alpha/include/intr.h
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/powerpc/pic/ipi.c
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/powerpc/pic/ipivar.h
cvs rdiff -u -r1.222 -r1.223 src/sys/arch/sparc/sparc/cpu.c
cvs rdiff -u -r1.38 -r1.39 src/sys/arch/sparc64/sparc64/ipifuncs.c
cvs rdiff -u -r1.87 -r1.88 src/sys/arch/vax/include/cpu.h
cvs rdiff -u -r1.28 -r1.29 src/sys/arch/vax/vax/multicpu.c
cvs rdiff -u -r1.15 -r1.16 src/sys/arch/x86/include/intrdefs.h
cvs rdiff -u -r1.17 -r1.18 src/sys/arch/x86/x86/ipi.c
cvs rdiff -u -r1.11 -r1.12 src/sys/kern/subr_xcall.c
cvs rdiff -u -r1.3 -r1.4 src/sys/sys/xcall.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/alpha/alpha/ipifuncs.c
diff -u src/sys/arch/alpha/alpha/ipifuncs.c:1.41 src/sys/arch/alpha/alpha/ipifuncs.c:1.42
--- src/sys/arch/alpha/alpha/ipifuncs.c:1.41	Mon Oct 26 03:51:42 2009
+++ src/sys/arch/alpha/alpha/ipifuncs.c	Tue Jun 22 18:29:01 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: ipifuncs.c,v 1.41 2009/10/26 03:51:42 thorpej Exp $ */
+/* $NetBSD: ipifuncs.c,v 1.42 2010/06/22 18:29:01 rmind Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.41 2009/10/26 03:51:42 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.42 2010/06/22 18:29:01 rmind Exp $");
 
 /*
  * Interprocessor interrupt handlers.
@@ -64,6 +64,7 @@
 void	alpha_ipi_synch_fpu(struct cpu_info *, struct trapframe *);
 void	alpha_ipi_discard_fpu(struct cpu_info *, struct trapframe *);
 void	alpha_ipi_pause(struct cpu_info *, struct trapframe *);
+void	alpha_ipi_xcall(struct cpu_info *, struct trapframe *);
 
 /*
  * NOTE: This table must be kept in order with the bit definitions
@@ -78,6 +79,7 @@
 	alpha_ipi_synch_fpu,
 	alpha_ipi_discard_fpu,
 	alpha_ipi_pause,
+	alpha_ipi_xcall
 };
 
 const char *ipinames[ALPHA_NIPIS] = {
@@ -89,6 +91,7 @@
 	"synch fpu ipi",
 	"discard fpu ipi",
 	"pause ipi",
+	"xcall ipi"
 };
 
 /*
@@ -309,3 +312,30 @@
 	/* Do an IMB on the way out, in case the kernel text was changed. */
 	alpha_pal_imb();
 }
+
+/*
+ * MD support for xcall(9) interface.
+ */
+
+static void
+alpha_ipi_xcall(struct cpu_info *ci, struct trapframe *framep)
+{
+
+	xc_ipi_handler();
+}
+
+void
+xc_send_ipi(struct cpu_info *ci)
+{
+
+	KASSERT(kpreempt_disabled());
+	KASSERT(curcpu() != ci);
+
+	if (ci) {
+		/* Unicast: remote CPU. */
+		alpha_send_ipi(ci->ci_cpuid, ALPHA_IPI_XCALL);
+	} else {
+		/* Broadcast: all, but local CPU (caller will handle it). */
+		alpha_broadcast_ipi(ALPHA_IPI_XCALL);
+	}
+}

Index: src/sys/arch/alpha/include/intr.h
diff -u src/sys/arch/alpha/include/intr.h:1.67 src/sys/arch/alpha/include/intr.h:1.68
--- src/sys/arch/alpha/include/intr.h:1.67	Mon Oct 26 03:51:43 2009
+++ src/sys/arch/alpha/include/intr.h	Tue Jun 22 18:29:02 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: intr.h,v 1.67 2009/10/26 03:51:43 thorpej Exp $ */
+/* $NetBSD: intr.h,v 1.68 2010/06/22 18:29:02 rmind Exp $ */
 
 /*-
  * Copyright (c) 2000, 2001, 2002 The NetBSD Foundation, Inc.
@@ -165,8 +165,9 @@
 #define	ALPHA_IPI_SYNCH_FPU		(1UL << 5)
 #define	ALPHA_IPI_DISCARD_FPU		(1UL << 6)
 #define	ALPHA_IPI_PAUSE			(1UL << 7)
+#define	ALPHA_IPI_XCALL			(1UL << 8)
 
-#define	ALPHA_NIPIS		8	/* must not exceed 64 */
+#define	ALPHA_NIPIS		9	/* must not exceed 64 */
 
 struct cpu_info;
 struct trapframe;

Index: src/sys/arch/powerpc/pic/ipi.c
diff -u src/sys/arch/powerpc/pic/ipi.c:1.4 src/sys/arch/powerpc/pic/ipi.c:1.5
--- src/sys/arch/powerpc/pic/ipi.c:1.4	Mon Apr 28 20:23:32 2008
+++ src/sys/arch/powerpc/pic/ipi.c	Tue Jun 22 18:29:02 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: ipi.c,v 1.4 2008/04/28 20:23:32 martin Exp $ */
+/* $NetBSD: ipi.c,v 1.5 2010/06/22 18:29:02 rmind Exp $ */
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipi.c,v 1.4 2008/04/28 20:23:32 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipi.c,v 1.5 2010/06/22 18:29:02 rmind Exp $");
 
 #include "opt_multiprocessor.h"
 #include "opt_pic.h"
@@ -76,6 +76,9 @@
 		save_vec_cpu();
 #endif
 
+	if (ipi & PPC_IPI_XCALL)
+		xc_ipi_handler();
+
 	if (ipi & PPC_IPI_HALT) {
 		aprint_normal("halting CPU %d\n", cpu_id);
 		msr = (mfmsr() & ~PSL_EE) | PSL_POW;
@@ -84,7 +87,28 @@
 			mtmsr(msr);
 		}
 	}
+
 	return 1;
 }
 
+/*
+ * MD support for xcall(9) interface.
+ */
+
+void
+xc_send_ipi(struct cpu_info *ci)
+{
+
+	KASSERT(kpreempt_disabled());
+	KASSERT(curcpu() != ci);
+
+	if (ci) {
+		/* Unicast: remote CPU. */
+		ppc_send_ipi(ci->ci_cpuid, PPC_IPI_XCALL);
+	} else {
+		/* Broadcast: all, but local CPU (caller will handle it). */
+		ppc_send_ipi(IPI_T_NOTME, PPC_IPI_XCALL);
+	}
+}
+
 #endif /*MULTIPROCESSOR*/

Index: src/sys/arch/powerpc/pic/ipivar.h
diff -u src/sys/arch/powerpc/pic/ipivar.h:1.3 src/sys/arch/powerpc/pic/ipivar.h:1.4
--- src/sys/arch/powerpc/pic/ipivar.h:1.3	Mon Apr 28 20:23:32 2008
+++ src/sys/arch/powerpc/pic/ipivar.h	Tue Jun 22 18:29:02 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: ipivar.h,v 1.3 2008/04/28 20:23:32 martin Exp $ */
+/* $NetBSD: ipivar.h,v 1.4 2010/06/22 18:29:02 rmind Exp $ */
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipivar.h,v 1.3 2008/04/28 20:23:32 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipivar.h,v 1.4 2010/06/22 18:29:02 rmind Exp $");
 
 #ifndef _IPI_VAR_H_
 #define _IPI_VAR_H_
@@ -51,6 +51,7 @@
 #define PPC_IPI_HALT		0x0001
 #define PPC_IPI_FLUSH_FPU	0x0002
 #define PPC_IPI_FLUSH_VEC	0x0004
+#define PPC_IPI_XCALL		0x0008
 
 /* OpenPIC */
 void setup_openpic_ipi(void);

Index: src/sys/arch/sparc/sparc/cpu.c
diff -u src/sys/arch/sparc/sparc/cpu.c:1.222 src/sys/arch/sparc/sparc/cpu.c:1.223
--- src/sys/arch/sparc/sparc/cpu.c:1.222	Mon May 31 03:16:47 2010
+++ src/sys/arch/sparc/sparc/cpu.c	Tue Jun 22 18:29:02 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu.c,v 1.222 2010/05/31 03:16:47 mrg Exp $ */
+/*	$NetBSD: cpu.c,v 1.223 2010/06/22 18:29:02 rmind Exp $ */
 
 /*
  * Copyright (c) 1996
@@ -52,7 +52,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.222 2010/05/31 03:16:47 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.223 2010/06/22 18:29:02 rmind Exp $");
 
 #include "opt_multiprocessor.h"
 #include "opt_lockdebug.h"
@@ -63,11 +63,8 @@
 #include <sys/systm.h>
 #include <sys/device.h>
 #include <sys/malloc.h>
-#include <sys/simplelock.h>
 #include <sys/kernel.h>
-#if 0
 #include <sys/xcall.h>
-#endif
 
 #include <uvm/uvm.h>
 
@@ -640,9 +637,8 @@
 	mutex_spin_exit(&xpmsg_mutex);
 }
 
-#if 0
 /*
- * MI interface to call xc_ipi_handler() everywhere.
+ * MD support for MI xcall(9) interface.
  */
 void
 xc_send_ipi(struct cpu_info *target)
@@ -658,7 +654,6 @@
 		cpuset = CPUSET_ALL & ~(1 << cpuinfo.ci_cpuid);
 	XCALL0(xc_ipi_handler, cpuset);
 }
-#endif
 
 /*
  * Tell all CPUs other than the current one to enter the PROM idle loop.

Index: src/sys/arch/sparc64/sparc64/ipifuncs.c
diff -u src/sys/arch/sparc64/sparc64/ipifuncs.c:1.38 src/sys/arch/sparc64/sparc64/ipifuncs.c:1.39
--- src/sys/arch/sparc64/sparc64/ipifuncs.c:1.38	Sat May 29 21:59:34 2010
+++ src/sys/arch/sparc64/sparc64/ipifuncs.c	Tue Jun 22 18:29:02 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipifuncs.c,v 1.38 2010/05/29 21:59:34 martin Exp $ */
+/*	$NetBSD: ipifuncs.c,v 1.39 2010/06/22 18:29:02 rmind Exp $ */
 
 /*-
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -27,14 +27,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.38 2010/05/29 21:59:34 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.39 2010/06/22 18:29:02 rmind Exp $");
 
 #include "opt_ddb.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/malloc.h>
-#include <sys/simplelock.h>
+#include <sys/xcall.h>
 
 #include <machine/db_machdep.h>
 
@@ -463,6 +463,10 @@
 	printf("\n");
 }
 
+/*
+ * MD support for xcall(9) interface.
+ */
+
 void
 sparc64_generic_xcall(struct cpu_info *target, ipi_c_call_func_t func,
 	void *arg)
@@ -478,14 +482,9 @@
 	}
 }
 
-#if 0
-/* XXX: remove once a public prototype is available */
-void	xc_ipi_handler(void);
-void	xc_send_ipi(struct cpu_info *);
-
 void
 xc_send_ipi(struct cpu_info *target)
 {
+
 	sparc64_generic_xcall(target, (ipi_c_call_func_t)xc_ipi_handler, NULL);
 }
-#endif

Index: src/sys/arch/vax/include/cpu.h
diff -u src/sys/arch/vax/include/cpu.h:1.87 src/sys/arch/vax/include/cpu.h:1.88
--- src/sys/arch/vax/include/cpu.h:1.87	Sat Dec 12 14:44:09 2009
+++ src/sys/arch/vax/include/cpu.h	Tue Jun 22 18:29:02 2010
@@ -1,4 +1,4 @@
-/*      $NetBSD: cpu.h,v 1.87 2009/12/12 14:44:09 tsutsui Exp $      */
+/*      $NetBSD: cpu.h,v 1.88 2010/06/22 18:29:02 rmind Exp $      */
 
 /*
  * Copyright (c) 1994 Ludd, University of Lule}, Sweden
@@ -101,6 +101,7 @@
 #define	IPI_RUNNING	3	/* This CPU just started to run */
 #define	IPI_TBIA	4	/* Flush the TLB */
 #define	IPI_DDB		5	/* Jump into the DDB loop */
+#define	IPI_XCALL	6	/* Helper for xcall(9) */
 
 #define	IPI_DEST_MASTER	-1	/* Destination is mastercpu */
 #define	IPI_DEST_ALL	-2	/* Broadcast */

Index: src/sys/arch/vax/vax/multicpu.c
diff -u src/sys/arch/vax/vax/multicpu.c:1.28 src/sys/arch/vax/vax/multicpu.c:1.29
--- src/sys/arch/vax/vax/multicpu.c:1.28	Thu Nov 26 00:19:23 2009
+++ src/sys/arch/vax/vax/multicpu.c	Tue Jun 22 18:29:02 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: multicpu.c,v 1.28 2009/11/26 00:19:23 matt Exp $	*/
+/*	$NetBSD: multicpu.c,v 1.29 2010/06/22 18:29:02 rmind Exp $	*/
 
 /*
  * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: multicpu.c,v 1.28 2009/11/26 00:19:23 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: multicpu.c,v 1.29 2010/06/22 18:29:02 rmind Exp $");
 
 #include "opt_multiprocessor.h"
 
@@ -44,6 +44,7 @@
 #include <sys/malloc.h>
 #include <sys/proc.h>
 #include <sys/device.h>
+#include <sys/xcall.h>
 
 #include <uvm/uvm_extern.h>
 
@@ -195,9 +196,32 @@
 		case IPI_DDB:
 			Debugger();
 			break;
+		case IPI_XCALL:
+			xc_ipi_handler();
+			break;
 		default:
 			panic("cpu_handle_ipi: bad bit %x", bitno);
 		}
 	}
 	splx(s);
 }
+
+/*
+ * MD support for xcall(9) interface.
+ */
+
+void
+xc_send_ipi(struct cpu_info *ci)
+{
+
+	KASSERT(kpreempt_disabled());
+	KASSERT(curcpu() != ci);
+
+	if (ci) {
+		/* Unicast: remote CPU. */
+		cpu_send_ipi(ci->ci_cpuid, IPI_XCALL);
+	} else {
+		/* Broadcast: all, but local CPU (caller will handle it). */
+		cpu_send_ipi(IPI_DEST_ALL, IPI_XCALL);
+	}
+}

Index: src/sys/arch/x86/include/intrdefs.h
diff -u src/sys/arch/x86/include/intrdefs.h:1.15 src/sys/arch/x86/include/intrdefs.h:1.16
--- src/sys/arch/x86/include/intrdefs.h:1.15	Mon Oct  5 23:59:31 2009
+++ src/sys/arch/x86/include/intrdefs.h	Tue Jun 22 18:29:02 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: intrdefs.h,v 1.15 2009/10/05 23:59:31 rmind Exp $	*/
+/*	$NetBSD: intrdefs.h,v 1.16 2010/06/22 18:29:02 rmind Exp $	*/
 
 #ifndef _X86_INTRDEFS_H_
 #define _X86_INTRDEFS_H_
@@ -62,7 +62,7 @@
 #define X86_IPI_SYNCH_FPU		0x00000008
 #define X86_IPI_MTRR			0x00000010
 #define X86_IPI_GDT			0x00000020
-#define X86_IPI__UNUSED2		0x00000040
+#define X86_IPI_XCALL			0x00000040
 #define X86_IPI_ACPI_CPU_SLEEP		0x00000080
 #define X86_IPI_KPREEMPT		0x00000100
 
@@ -70,7 +70,7 @@
 
 #define X86_IPI_NAMES { "halt IPI", "timeset IPI", "unused", \
 			 "FPU synch IPI", "MTRR update IPI", \
-			 "GDT update IPI", "unused", \
+			 "GDT update IPI", "xcall IPI", \
 			 "ACPI CPU sleep IPI", "kpreempt IPI" }
 
 #define IREENT_MAGIC	0x18041969

Index: src/sys/arch/x86/x86/ipi.c
diff -u src/sys/arch/x86/x86/ipi.c:1.17 src/sys/arch/x86/x86/ipi.c:1.18
--- src/sys/arch/x86/x86/ipi.c:1.17	Sun Apr 25 16:10:51 2010
+++ src/sys/arch/x86/x86/ipi.c	Tue Jun 22 18:29:03 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipi.c,v 1.17 2010/04/25 16:10:51 ad Exp $	*/
+/*	$NetBSD: ipi.c,v 1.18 2010/06/22 18:29:03 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2000, 2008, 2009 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipi.c,v 1.17 2010/04/25 16:10:51 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipi.c,v 1.18 2010/06/22 18:29:03 rmind Exp $");
 
 #include "opt_mtrr.h"
 
@@ -42,6 +42,7 @@
 #include <sys/atomic.h>
 #include <sys/intr.h>
 #include <sys/cpu.h>
+#include <sys/xcall.h>
  
 #ifdef MULTIPROCESSOR
 
@@ -71,6 +72,7 @@
 
 static void	x86_ipi_halt(struct cpu_info *);
 static void	x86_ipi_kpreempt(struct cpu_info *);
+static void	x86_ipi_xcall(struct cpu_info *);
 
 #ifdef MTRR
 static void	x86_ipi_reload_mtrr(struct cpu_info *);
@@ -92,7 +94,7 @@
 	x86_ipi_synch_fpu,
 	x86_ipi_reload_mtrr,
 	gdt_reload_cpu,
-	NULL,
+	x86_ipi_xcall,
 	acpi_cpu_sleep,
 	x86_ipi_kpreempt
 };
@@ -209,6 +211,33 @@
 	softint_trigger(1 << SIR_PREEMPT);
 }
 
+/*
+ * MD support for xcall(9) interface.
+ */
+
+static void
+x86_ipi_xcall(struct cpu_info *ci)
+{
+
+	xc_ipi_handler();
+}
+
+void
+xc_send_ipi(struct cpu_info *ci)
+{
+
+	KASSERT(kpreempt_disabled());
+	KASSERT(curcpu() != ci);
+
+	if (ci) {
+		/* Unicast: remote CPU. */
+		x86_send_ipi(ci, X86_IPI_XCALL);
+	} else {
+		/* Broadcast: all, but local CPU (caller will handle it). */
+		x86_broadcast_ipi(X86_IPI_XCALL);
+	}
+}
+
 #else
 
 int

Index: src/sys/kern/subr_xcall.c
diff -u src/sys/kern/subr_xcall.c:1.11 src/sys/kern/subr_xcall.c:1.12
--- src/sys/kern/subr_xcall.c:1.11	Mon Nov 30 15:37:56 2009
+++ src/sys/kern/subr_xcall.c	Tue Jun 22 18:29:01 2010
@@ -1,11 +1,11 @@
-/*	$NetBSD: subr_xcall.c,v 1.11 2009/11/30 15:37:56 pooka Exp $	*/
+/*	$NetBSD: subr_xcall.c,v 1.12 2010/06/22 18:29:01 rmind Exp $	*/
 
 /*-
- * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 2007-2010 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
- * by Andrew Doran.
+ * by Andrew Doran and Mindaugas Rasiukevicius.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -67,14 +67,14 @@
  *	Cross calls must not allocate memory, as the pagedaemon uses
  *	them (and memory allocation may need to wait on the pagedaemon).
  *
- * Future directions
- *
- *	Add a low-overhead mechanism to run cross calls in interrupt
- *	context (XC_HIGHPRI).
+ *	A low-overhead mechanism for high priority calls (XC_HIGHPRI) is
+ *	also provided.  The function to be executed runs on a software
+ *	interrupt context, at SOFTINT_CLOCK level, and is expected to be
+ *	very lightweight, e.g. avoid blocking.
  */
  
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_xcall.c,v 1.11 2009/11/30 15:37:56 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_xcall.c,v 1.12 2010/06/22 18:29:01 rmind Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -85,19 +85,66 @@
 #include <sys/kthread.h>
 #include <sys/cpu.h>
 
-static void	xc_thread(void *);
-static uint64_t	xc_lowpri(u_int, xcfunc_t, void *, void *, struct cpu_info *);
+/* Cross-call state box. */
+typedef struct {
+	kmutex_t	xc_lock;
+	kcondvar_t	xc_busy;
+	xcfunc_t	xc_func;
+	void *		xc_arg1;
+	void *		xc_arg2;
+	uint64_t	xc_headp;
+	uint64_t	xc_donep;
+} xc_state_t;
+
+/* Bit indicating high (1) or low (0) priority. */
+#define	XC_PRI_BIT	(1ULL << 63)
+
+/* Low priority xcall structures. */
+static xc_state_t	xc_low_pri;
+static uint64_t		xc_tailp;
+
+/* High priority xcall structures. */
+static xc_state_t	xc_high_pri;
+static void *		xc_sih;
 
-static kmutex_t		xc_lock;
-static xcfunc_t		xc_func;
-static void		*xc_arg1;
-static void		*xc_arg2;
-static kcondvar_t	xc_busy;
+/* Event counters. */
 static struct evcnt	xc_unicast_ev;
 static struct evcnt	xc_broadcast_ev;
-static uint64_t		xc_headp;
-static uint64_t		xc_tailp;
-static uint64_t		xc_donep;
+
+static void		xc_init(void);
+static void		xc_thread(void *);
+static void		xc_highpri_intr(void *);
+
+static inline uint64_t	xc_highpri(xcfunc_t, void *, void *, struct cpu_info *);
+static inline uint64_t	xc_lowpri(xcfunc_t, void *, void *, struct cpu_info *);
+
+/*
+ * xc_init:
+ *
+ *	Initialize low and high priority cross-call structures.
+ */
+static void
+xc_init(void)
+{
+	xc_state_t *xclo = &xc_low_pri, *xchi = &xc_high_pri;
+
+	memset(xclo, 0, sizeof(xc_state_t));
+	mutex_init(&xclo->xc_lock, MUTEX_DEFAULT, IPL_NONE);
+	cv_init(&xclo->xc_busy, "xclocv");
+	xc_tailp = 0;
+
+	memset(xchi, 0, sizeof(xc_state_t));
+	mutex_init(&xchi->xc_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK);
+	cv_init(&xchi->xc_busy, "xchicv");
+	xc_sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE,
+	    xc_highpri_intr, NULL);
+	KASSERT(xc_sih != NULL);
+
+	evcnt_attach_dynamic(&xc_unicast_ev, EVCNT_TYPE_MISC, NULL,
+	   "crosscall", "unicast");
+	evcnt_attach_dynamic(&xc_broadcast_ev, EVCNT_TYPE_MISC, NULL,
+	   "crosscall", "broadcast");
+}
 
 /*
  * xc_init_cpu:
@@ -113,20 +160,13 @@
 
 	if (!again) {
 		/* Autoconfiguration will prevent re-entry. */
+		xc_init();
 		again = true;
-		mutex_init(&xc_lock, MUTEX_DEFAULT, IPL_NONE);
-		cv_init(&xc_busy, "xcallbsy");
-		evcnt_attach_dynamic(&xc_unicast_ev, EVCNT_TYPE_MISC, NULL,
-		   "crosscall", "unicast");
-		evcnt_attach_dynamic(&xc_broadcast_ev, EVCNT_TYPE_MISC, NULL,
-		   "crosscall", "broadcast");
 	}
-
 	cv_init(&ci->ci_data.cpu_xcall, "xcall");
 	error = kthread_create(PRI_XCALL, KTHREAD_MPSAFE, ci, xc_thread,
 	    NULL, NULL, "xcall/%u", ci->ci_index);
-	if (error != 0)
-		panic("xc_init_cpu: error %d", error);
+	KASSERT(error == 0);
 }
 
 /*
@@ -138,10 +178,12 @@
 xc_broadcast(u_int flags, xcfunc_t func, void *arg1, void *arg2)
 {
 
+	KASSERT(!cpu_intr_p() && !cpu_softintr_p());
+
 	if ((flags & XC_HIGHPRI) != 0) {
-		panic("xc_broadcast: no high priority crosscalls yet");
+		return xc_highpri(func, arg1, arg2, NULL);
 	} else {
-		return xc_lowpri(flags, func, arg1, arg2, NULL);
+		return xc_lowpri(func, arg1, arg2, NULL);
 	}
 }
 
@@ -155,12 +197,47 @@
 	   struct cpu_info *ci)
 {
 
+	KASSERT(ci != NULL);
+	KASSERT(!cpu_intr_p() && !cpu_softintr_p());
+
 	if ((flags & XC_HIGHPRI) != 0) {
-		panic("xc_unicast: no high priority crosscalls yet");
+		return xc_highpri(func, arg1, arg2, ci);
+	} else {
+		return xc_lowpri(func, arg1, arg2, ci);
+	}
+}
+
+/*
+ * xc_wait:
+ *
+ *	Wait for a cross call to complete.
+ */
+void
+xc_wait(uint64_t where)
+{
+	xc_state_t *xc;
+
+	KASSERT(!cpu_intr_p() && !cpu_softintr_p());
+
+	/* Determine whether it is high or low priority cross-call. */
+	if ((where & XC_PRI_BIT) != 0) {
+		xc = &xc_high_pri;
+		where &= ~XC_PRI_BIT;
 	} else {
-		KASSERT(ci != NULL);
-		return xc_lowpri(flags, func, arg1, arg2, ci);
+		xc = &xc_low_pri;
+	}
+
+	/* Fast path, if already done. */
+	if (xc->xc_donep >= where) {
+		return;
+	}
+
+	/* Slow path: block until awoken. */
+	mutex_enter(&xc->xc_lock);
+	while (xc->xc_donep < where) {
+		cv_wait(&xc->xc_busy, &xc->xc_lock);
 	}
+	mutex_exit(&xc->xc_lock);
 }
 
 /*
@@ -168,60 +245,45 @@
  *
  *	Trigger a low priority call on one or more CPUs.
  */
-static uint64_t
-xc_lowpri(u_int flags, xcfunc_t func, void *arg1, void *arg2,
-	  struct cpu_info *ci)
+static inline uint64_t
+xc_lowpri(xcfunc_t func, void *arg1, void *arg2, struct cpu_info *ci)
 {
+	xc_state_t *xc = &xc_low_pri;
 	CPU_INFO_ITERATOR cii;
 	uint64_t where;
 
-	mutex_enter(&xc_lock);
-	while (xc_headp != xc_tailp)
-		cv_wait(&xc_busy, &xc_lock);
-	xc_arg1 = arg1;
-	xc_arg2 = arg2;
-	xc_func = func;
+	mutex_enter(&xc->xc_lock);
+	while (xc->xc_headp != xc_tailp) {
+		cv_wait(&xc->xc_busy, &xc->xc_lock);
+	}
+	xc->xc_arg1 = arg1;
+	xc->xc_arg2 = arg2;
+	xc->xc_func = func;
 	if (ci == NULL) {
 		xc_broadcast_ev.ev_count++;
 		for (CPU_INFO_FOREACH(cii, ci)) {
 			if ((ci->ci_schedstate.spc_flags & SPCF_RUNNING) == 0)
 				continue;
-			xc_headp += 1;
+			xc->xc_headp += 1;
 			ci->ci_data.cpu_xcall_pending = true;
 			cv_signal(&ci->ci_data.cpu_xcall);
 		}
 	} else {
 		xc_unicast_ev.ev_count++;
-		xc_headp += 1;
+		xc->xc_headp += 1;
 		ci->ci_data.cpu_xcall_pending = true;
 		cv_signal(&ci->ci_data.cpu_xcall);
 	}
-	KASSERT(xc_tailp < xc_headp);
-	where = xc_headp;
-	mutex_exit(&xc_lock);
+	KASSERT(xc_tailp < xc->xc_headp);
+	where = xc->xc_headp;
+	mutex_exit(&xc->xc_lock);
 
+	/* Return a low priority ticket. */
+	KASSERT((where & XC_PRI_BIT) == 0);
 	return where;
 }
 
 /*
- * xc_wait:
- *
- *	Wait for a cross call to complete.
- */
-void
-xc_wait(uint64_t where)
-{
-
-	if (xc_donep >= where)
-		return;
-
-	mutex_enter(&xc_lock);
-	while (xc_donep < where)
-		cv_wait(&xc_busy, &xc_lock);
-	mutex_exit(&xc_lock);
-}
-
-/*
  * xc_thread:
  *
  *	One thread per-CPU to dispatch low priority calls.
@@ -229,31 +291,130 @@
 static void
 xc_thread(void *cookie)
 {
+	struct cpu_info *ci = curcpu();
+	xc_state_t *xc = &xc_low_pri;
 	void *arg1, *arg2;
-	struct cpu_info *ci;
 	xcfunc_t func;
 
-	ci = curcpu();
-
-	mutex_enter(&xc_lock);
+	mutex_enter(&xc->xc_lock);
 	for (;;) {
 		while (!ci->ci_data.cpu_xcall_pending) {
-			if (xc_headp == xc_tailp)
-				cv_broadcast(&xc_busy);
-			cv_wait(&ci->ci_data.cpu_xcall, &xc_lock);
+			if (xc->xc_headp == xc_tailp) {
+				cv_broadcast(&xc->xc_busy);
+			}
+			cv_wait(&ci->ci_data.cpu_xcall, &xc->xc_lock);
 			KASSERT(ci == curcpu());
 		}
 		ci->ci_data.cpu_xcall_pending = false;
-		func = xc_func;
-		arg1 = xc_arg1;
-		arg2 = xc_arg2;
+		func = xc->xc_func;
+		arg1 = xc->xc_arg1;
+		arg2 = xc->xc_arg2;
 		xc_tailp++;
-		mutex_exit(&xc_lock);
+		mutex_exit(&xc->xc_lock);
 
+		KASSERT(func != NULL);
 		(*func)(arg1, arg2);
 
-		mutex_enter(&xc_lock);
-		xc_donep++;
+		mutex_enter(&xc->xc_lock);
+		xc->xc_donep++;
 	}
 	/* NOTREACHED */
 }
+
+/*
+ * xc_ipi_handler:
+ *
+ *	Handler of cross-call IPI.
+ */
+void
+xc_ipi_handler(void)
+{
+	/* Executes xc_highpri_intr() via software interrupt. */
+	softint_schedule(xc_sih);
+}
+
+/*
+ * xc_highpri_intr:
+ *
+ *	A software interrupt handler for high priority calls.
+ */
+static void
+xc_highpri_intr(void *dummy)
+{
+	xc_state_t *xc = &xc_high_pri;
+	void *arg1, *arg2;
+	xcfunc_t func;
+
+	KASSERT(cpu_softintr_p());
+	/*
+	 * Lock-less fetch of function and its arguments.
+	 * Safe since it cannot change at this point.
+	 */
+	KASSERT(xc->xc_donep < xc->xc_headp);
+	func = xc->xc_func;
+	arg1 = xc->xc_arg1;
+	arg2 = xc->xc_arg2;
+
+	KASSERT(func != NULL);
+	(*func)(arg1, arg2);
+
+	/*
+	 * Note the request as done, and if we have reached the head,
+	 * cross-call has been processed - notify waiters, if any.
+	 */
+	mutex_enter(&xc->xc_lock);
+	if (++xc->xc_donep == xc->xc_headp) {
+		cv_broadcast(&xc->xc_busy);
+	}
+	mutex_exit(&xc->xc_lock);
+}
+
+/*
+ * xc_highpri:
+ *
+ *	Trigger a high priority call on one or more CPUs.
+ */
+static inline uint64_t
+xc_highpri(xcfunc_t func, void *arg1, void *arg2, struct cpu_info *ci)
+{
+	xc_state_t *xc = &xc_high_pri;
+	uint64_t where;
+
+	mutex_enter(&xc->xc_lock);
+	while (xc->xc_headp != xc->xc_donep) {
+		cv_wait(&xc->xc_busy, &xc->xc_lock);
+	}
+	xc->xc_func = func;
+	xc->xc_arg1 = arg1;
+	xc->xc_arg2 = arg2;
+	xc->xc_headp += (ci ? 1 : ncpu);
+	where = xc->xc_headp;
+	mutex_exit(&xc->xc_lock);
+
+	/*
+	 * Send the IPI once lock is released.
+	 * Note: it will handle the local CPU case.
+	 */
+
+#ifdef MULTIPROCESSOR
+	kpreempt_disable();
+	if (curcpu() == ci) {
+		/* Unicast: local CPU. */
+		xc_ipi_handler();
+	} else if (ci) {
+		/* Unicast: remote CPU. */
+		xc_send_ipi(ci);
+	} else {
+		/* Broadcast: all, including local. */
+		xc_send_ipi(NULL);
+		xc_ipi_handler();
+	}
+	kpreempt_enable();
+#else
+	KASSERT(curcpu() == ci);
+	xc_ipi_handler();
+#endif
+
+	/* Indicate a high priority ticket. */
+	return (where | XC_PRI_BIT);
+}

Index: src/sys/sys/xcall.h
diff -u src/sys/sys/xcall.h:1.3 src/sys/sys/xcall.h:1.4
--- src/sys/sys/xcall.h:1.3	Mon Apr 28 20:24:11 2008
+++ src/sys/sys/xcall.h	Tue Jun 22 18:29:01 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: xcall.h,v 1.3 2008/04/28 20:24:11 martin Exp $	*/
+/*	$NetBSD: xcall.h,v 1.4 2010/06/22 18:29:01 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -40,6 +40,9 @@
 struct cpu_info;
 
 void		xc_init_cpu(struct cpu_info *);
+void		xc_send_ipi(struct cpu_info *);
+void		xc_ipi_handler(void);
+
 uint64_t	xc_broadcast(u_int, xcfunc_t, void *, void *);
 uint64_t	xc_unicast(u_int, xcfunc_t, void *, void *, struct cpu_info *);
 void		xc_wait(uint64_t);

Reply via email to