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