Module Name:    src
Committed By:   rmind
Date:           Sun May 25 15:42:01 UTC 2014

Modified Files:
        src/sys/kern: kern_softint.c
        src/sys/sys: intr.h

Log Message:
softint: implement softint_schedule_cpu() to trigger software interrupts
on the remote CPUs and add SOFTINT_RCPU flag to indicate whether this is
going to be used; implemented using asynchronous IPIs.


To generate a diff of this commit:
cvs rdiff -u -r1.40 -r1.41 src/sys/kern/kern_softint.c
cvs rdiff -u -r1.16 -r1.17 src/sys/sys/intr.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/kern/kern_softint.c
diff -u src/sys/kern/kern_softint.c:1.40 src/sys/kern/kern_softint.c:1.41
--- src/sys/kern/kern_softint.c:1.40	Sat Sep  7 03:34:59 2013
+++ src/sys/kern/kern_softint.c	Sun May 25 15:42:01 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_softint.c,v 1.40 2013/09/07 03:34:59 matt Exp $	*/
+/*	$NetBSD: kern_softint.c,v 1.41 2014/05/25 15:42:01 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
@@ -167,20 +167,15 @@
  *	execution as a normal LWP (kthread) and gains VM context.  Only
  *	when it has completed and is ready to fire again will it
  *	interrupt other threads.
- *
- * Future directions
- *
- *	Provide a cheap way to direct software interrupts to remote
- *	CPUs.  Provide a way to enqueue work items into the handler
- *	record,	removing additional spl calls (see subr_workqueue.c). 
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_softint.c,v 1.40 2013/09/07 03:34:59 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_softint.c,v 1.41 2014/05/25 15:42:01 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
 #include <sys/intr.h>
+#include <sys/ipi.h>
 #include <sys/mutex.h>
 #include <sys/kthread.h>
 #include <sys/evcnt.h>
@@ -211,6 +206,7 @@ typedef struct softhand {
 	void			*sh_arg;
 	softint_t		*sh_isr;
 	u_int			sh_flags;
+	u_int			sh_ipi_id;
 } softhand_t;
 
 typedef struct softcpu {
@@ -338,6 +334,8 @@ softint_establish(u_int flags, void (*fu
 	softcpu_t *sc;
 	softhand_t *sh;
 	u_int level, index;
+	u_int ipi_id = 0;
+	void *sih;
 
 	level = (flags & SOFTINT_LVLMASK);
 	KASSERT(level < SOFTINT_COUNT);
@@ -357,6 +355,14 @@ softint_establish(u_int flags, void (*fu
 		    "increase softint_bytes\n");
 		return NULL;
 	}
+	sih = (void *)((uint8_t *)&sc->sc_hand[index] - (uint8_t *)sc);
+
+	if (flags & SOFTINT_RCPU) {
+		if ((ipi_id = ipi_register(softint_schedule, sih)) == 0) {
+			mutex_exit(&softint_lock);
+			return NULL;
+		}
+	}
 
 	/* Set up the handler on each CPU. */
 	if (ncpu < 2) {
@@ -367,6 +373,7 @@ softint_establish(u_int flags, void (*fu
 		sh->sh_func = func;
 		sh->sh_arg = arg;
 		sh->sh_flags = flags;
+		sh->sh_ipi_id = ipi_id;
 	} else for (CPU_INFO_FOREACH(cii, ci)) {
 		sc = ci->ci_data.cpu_softcpu;
 		sh = &sc->sc_hand[index];
@@ -374,11 +381,11 @@ softint_establish(u_int flags, void (*fu
 		sh->sh_func = func;
 		sh->sh_arg = arg;
 		sh->sh_flags = flags;
+		sh->sh_ipi_id = ipi_id;
 	}
-
 	mutex_exit(&softint_lock);
 
-	return (void *)((uint8_t *)&sc->sc_hand[index] - (uint8_t *)sc);
+	return sih;
 }
 
 /*
@@ -407,6 +414,16 @@ softint_disestablish(void *arg)
 	    offset, softint_bytes);
 
 	/*
+	 * Unregister an IPI handler if there is any.  Note: there is
+	 * no need to disable preemption here - ID is stable.
+	 */
+	sc = curcpu()->ci_data.cpu_softcpu;
+	sh = (softhand_t *)((uint8_t *)sc + offset);
+	if (sh->sh_ipi_id) {
+		ipi_unregister(sh->sh_ipi_id);
+	}
+
+	/*
 	 * Run a cross call so we see up to date values of sh_flags from
 	 * all CPUs.  Once softint_disestablish() is called, the caller
 	 * commits to not trigger the interrupt and set SOFTINT_ACTIVE on
@@ -490,6 +507,33 @@ softint_schedule(void *arg)
 }
 
 /*
+ * softint_schedule_cpu:
+ *
+ *	Trigger a software interrupt on a target CPU.  This invokes
+ *	softint_schedule() for the local CPU or send an IPI to invoke
+ *	this routine on the remote CPU.  Preemption must be disabled.
+ */
+void
+softint_schedule_cpu(void *arg, struct cpu_info *ci)
+{
+	KASSERT(kpreempt_disabled());
+
+	if (curcpu() != ci) {
+		const softcpu_t *sc = ci->ci_data.cpu_softcpu;
+		const uintptr_t offset = (uintptr_t)arg;
+		const softhand_t *sh;
+
+		sh = (const softhand_t *)((const uint8_t *)sc + offset);
+		KASSERT((sh->sh_flags & SOFTINT_RCPU) != 0);
+		ipi_trigger(sh->sh_ipi_id, ci);
+		return;
+	}
+
+	/* Just a local CPU. */
+	softint_schedule(arg);
+}
+
+/*
  * softint_execute:
  *
  *	Invoke handlers for the specified soft interrupt.
@@ -548,7 +592,7 @@ softint_execute(softint_t *si, lwp_t *l,
 		KASSERTMSG(curcpu()->ci_mtx_count == 0,
 		    "%s: ci_mtx_count (%d) != 0, sh_func %p\n",
 		    __func__, curcpu()->ci_mtx_count, sh->sh_func);
-	
+
 		(void)splhigh();
 		KASSERT((sh->sh_flags & SOFTINT_ACTIVE) != 0);
 		sh->sh_flags ^= SOFTINT_ACTIVE;

Index: src/sys/sys/intr.h
diff -u src/sys/sys/intr.h:1.16 src/sys/sys/intr.h:1.17
--- src/sys/sys/intr.h:1.16	Sun Aug 25 03:08:56 2013
+++ src/sys/sys/intr.h	Sun May 25 15:42:01 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: intr.h,v 1.16 2013/08/25 03:08:56 matt Exp $	*/
+/*	$NetBSD: intr.h,v 1.17 2014/05/25 15:42:01 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -42,6 +42,7 @@ struct cpu_info;
 void	*softint_establish(u_int, void (*)(void *), void *);
 void	softint_disestablish(void *);
 void	softint_schedule(void *);
+void	softint_schedule_cpu(void *, struct cpu_info *);
 
 /* MI hooks. */
 void	softint_init(struct cpu_info *);
@@ -62,6 +63,7 @@ void	softint_dispatch(lwp_t *, int);
 #define	SOFTINT_SERIAL	0x0002
 #define	SOFTINT_NET	0x0003
 #define	SOFTINT_MPSAFE	0x0100
+#define	SOFTINT_RCPU	0x0200
 
 /* Implementation private flags. */
 #define	SOFTINT_PENDING	0x1000

Reply via email to