Module Name: src Committed By: snj Date: Mon Feb 19 18:33:38 UTC 2018
Modified Files: src/share/man/man9 [netbsd-8]: xcall.9 src/sys/kern [netbsd-8]: subr_psref.c subr_xcall.c src/sys/sys [netbsd-8]: xcall.h Log Message: Pull up following revision(s) (requested by ozaki-r in ticket #556): sys/sys/xcall.h: 1.6 share/man/man9/xcall.9: 1.11-1.12 sys/kern/subr_xcall.c: 1.21-1.25 Refer softint(9) -- Support arbitrary softint IPLs in high priority xcall The high priority xcall supported only a softint of IPL_SOFTSERIAL. It meant that it didn't work for xcall callbacks depending on lower IPLs than IPL_SOFTSERIAL. The change makes xcall have multiple softints of IPLs and allow users to specify arbitrary IPLs. Users can specify an IPL by XC_HIGHPRI_IPL passed to the 1st argument of xc_broadcast or xc_unicast. Note that xcall still serves requests one by one (i.e., doesn't run them concurrently) even if requests have different IPLs. Proposed on tech-kern@ -- Use high priority xcall with a softint of an IPL the same as psref class's one This mitigates undesired delay of psref_target_destroy under load such as heavy netowrk traffic that loads softint. -- Try to fix the build: avoid duplicate case labels when IPL_SOFT* are all the same. -- Fix build of kernels that some (or all) IPL_SOFT* share a value (e.g., mips) -- Avoid allocating unused softints that share a value of IPL between another Sort XC_IPL_* in order of priority (NFC) To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.10.18.1 src/share/man/man9/xcall.9 cvs rdiff -u -r1.7.2.2 -r1.7.2.3 src/sys/kern/subr_psref.c cvs rdiff -u -r1.19 -r1.19.8.1 src/sys/kern/subr_xcall.c cvs rdiff -u -r1.5 -r1.5.30.1 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/share/man/man9/xcall.9 diff -u src/share/man/man9/xcall.9:1.10 src/share/man/man9/xcall.9:1.10.18.1 --- src/share/man/man9/xcall.9:1.10 Tue Nov 26 20:48:25 2013 +++ src/share/man/man9/xcall.9 Mon Feb 19 18:33:38 2018 @@ -1,4 +1,4 @@ -.\" $NetBSD: xcall.9,v 1.10 2013/11/26 20:48:25 rmind Exp $ +.\" $NetBSD: xcall.9,v 1.10.18.1 2018/02/19 18:33:38 snj Exp $ .\" .\" Copyright (c) 2010 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd November 26, 2013 +.Dd February 1, 2018 .Dt XCALL 9 .Os .Sh NAME @@ -87,7 +87,6 @@ also provides a mechanism for making .Dq "high priority" cross calls. The function to be executed runs on the remote CPU within a -.Dv IPL_SOFTSERIAL software interrupt context, possibly interrupting other lower-priority code running on the CPU. .Sh NOTES @@ -112,7 +111,18 @@ on for the cross-call to complete. .Fa flags should be .Dv XC_HIGHPRI +or +.Fo XC_HIGHPRI_IPL +.Fa ipl +.Fc for a "high priority" call, and 0 for a "low priority" call. +.Dv XC_HIGHPRI +uses an +.Dv IPL_SOFTSERIAL +software interrupt while +.Fn XC_HIGHPRI_IPL +uses a software interrupt with an IPL specified by +.Fa ipl . .Fn xc_broadcast should not be called from interrupt context. .It Fn xc_unicast "flags" "func" "arg1" "arg2" "ci" @@ -144,7 +154,8 @@ interface is implemented within the file .\" .Sh EXAMPLES .Sh SEE ALSO .Xr kpreempt 9 , -.Xr percpu 9 +.Xr percpu 9 , +.Xr softint 9 .Sh HISTORY The .Nm Index: src/sys/kern/subr_psref.c diff -u src/sys/kern/subr_psref.c:1.7.2.2 src/sys/kern/subr_psref.c:1.7.2.3 --- src/sys/kern/subr_psref.c:1.7.2.2 Mon Jan 22 12:30:20 2018 +++ src/sys/kern/subr_psref.c Mon Feb 19 18:33:38 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: subr_psref.c,v 1.7.2.2 2018/01/22 12:30:20 martin Exp $ */ +/* $NetBSD: subr_psref.c,v 1.7.2.3 2018/02/19 18:33:38 snj Exp $ */ /*- * Copyright (c) 2016 The NetBSD Foundation, Inc. @@ -64,7 +64,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: subr_psref.c,v 1.7.2.2 2018/01/22 12:30:20 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_psref.c,v 1.7.2.3 2018/02/19 18:33:38 snj Exp $"); #include <sys/types.h> #include <sys/condvar.h> @@ -94,6 +94,7 @@ struct psref_class { kcondvar_t prc_cv; struct percpu *prc_percpu; /* struct psref_cpu */ ipl_cookie_t prc_iplcookie; + unsigned int prc_xc_flags; }; /* @@ -124,6 +125,7 @@ psref_class_create(const char *name, int mutex_init(&class->prc_lock, MUTEX_DEFAULT, ipl); cv_init(&class->prc_cv, name); class->prc_iplcookie = makeiplcookie(ipl); + class->prc_xc_flags = XC_HIGHPRI_IPL(ipl); return class; } @@ -434,7 +436,8 @@ psreffed_p(struct psref_target *target, * Ask all CPUs to say whether they hold a psref to the * target. */ - xc_wait(xc_broadcast(0, &psreffed_p_xc, &P, NULL)); + xc_wait(xc_broadcast(class->prc_xc_flags, &psreffed_p_xc, &P, + NULL)); } else psreffed_p_xc(&P, NULL); Index: src/sys/kern/subr_xcall.c diff -u src/sys/kern/subr_xcall.c:1.19 src/sys/kern/subr_xcall.c:1.19.8.1 --- src/sys/kern/subr_xcall.c:1.19 Mon Nov 21 00:54:21 2016 +++ src/sys/kern/subr_xcall.c Mon Feb 19 18:33:38 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: subr_xcall.c,v 1.19 2016/11/21 00:54:21 ozaki-r Exp $ */ +/* $NetBSD: subr_xcall.c,v 1.19.8.1 2018/02/19 18:33:38 snj Exp $ */ /*- * Copyright (c) 2007-2010 The NetBSD Foundation, Inc. @@ -74,7 +74,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: subr_xcall.c,v 1.19 2016/11/21 00:54:21 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_xcall.c,v 1.19.8.1 2018/02/19 18:33:38 snj Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -98,6 +98,7 @@ typedef struct { void * xc_arg2; uint64_t xc_headp; uint64_t xc_donep; + unsigned int xc_ipl; } xc_state_t; /* Bit indicating high (1) or low (0) priority. */ @@ -108,7 +109,7 @@ static xc_state_t xc_low_pri __cacheline /* High priority xcall structures. */ static xc_state_t xc_high_pri __cacheline_aligned; -static void * xc_sih __cacheline_aligned; +static void * xc_sihs[4] __cacheline_aligned; /* Event counters. */ static struct evcnt xc_unicast_ev __cacheline_aligned; @@ -117,9 +118,24 @@ static struct evcnt xc_broadcast_ev __ca static void xc_init(void); static void xc_thread(void *); -static inline uint64_t xc_highpri(xcfunc_t, void *, void *, struct cpu_info *); +static inline uint64_t xc_highpri(xcfunc_t, void *, void *, struct cpu_info *, + unsigned int); static inline uint64_t xc_lowpri(xcfunc_t, void *, void *, struct cpu_info *); +/* The internal form of IPL */ +#define XC_IPL_MASK 0xff00 +/* + * Assign 0 to XC_IPL_SOFTSERIAL to treat IPL_SOFTSERIAL as the default value + * (just XC_HIGHPRI). + */ +#define XC_IPL_SOFTSERIAL 0 +#define XC_IPL_SOFTNET 1 +#define XC_IPL_SOFTBIO 2 +#define XC_IPL_SOFTCLOCK 3 +#define XC_IPL_MAX XC_IPL_SOFTCLOCK + +CTASSERT(XC_IPL_MAX <= __arraycount(xc_sihs)); + /* * xc_init: * @@ -137,9 +153,31 @@ xc_init(void) memset(xchi, 0, sizeof(xc_state_t)); mutex_init(&xchi->xc_lock, MUTEX_DEFAULT, IPL_SOFTSERIAL); cv_init(&xchi->xc_busy, "xchicv"); - xc_sih = softint_establish(SOFTINT_SERIAL | SOFTINT_MPSAFE, - xc__highpri_intr, NULL); - KASSERT(xc_sih != NULL); + + /* Set up a softint for each IPL_SOFT*. */ +#define SETUP_SOFTINT(xipl, sipl) do { \ + xc_sihs[(xipl)] = softint_establish( (sipl) | SOFTINT_MPSAFE,\ + xc__highpri_intr, NULL); \ + KASSERT(xc_sihs[(xipl)] != NULL); \ + } while (0) + + SETUP_SOFTINT(XC_IPL_SOFTSERIAL, SOFTINT_SERIAL); + /* + * If a IPL_SOFTXXX have the same value of the previous, we don't use + * the IPL (see xc_encode_ipl). So we don't need to allocate a softint + * for it. + */ +#if IPL_SOFTNET != IPL_SOFTSERIAL + SETUP_SOFTINT(XC_IPL_SOFTNET, SOFTINT_NET); +#endif +#if IPL_SOFTBIO != IPL_SOFTNET + SETUP_SOFTINT(XC_IPL_SOFTBIO, SOFTINT_BIO); +#endif +#if IPL_SOFTCLOCK != IPL_SOFTBIO + SETUP_SOFTINT(XC_IPL_SOFTCLOCK, SOFTINT_CLOCK); +#endif + +#undef SETUP_SOFTINT evcnt_attach_dynamic(&xc_unicast_ev, EVCNT_TYPE_MISC, NULL, "crosscall", "unicast"); @@ -148,6 +186,45 @@ xc_init(void) } /* + * Encode an IPL to a form that can be embedded into flags of xc_broadcast + * or xc_unicast. + */ +unsigned int +xc_encode_ipl(int ipl) +{ + + switch (ipl) { + case IPL_SOFTSERIAL: + return __SHIFTIN(XC_IPL_SOFTSERIAL, XC_IPL_MASK); + /* IPL_SOFT* can be the same value (e.g., on sparc or mips). */ +#if IPL_SOFTNET != IPL_SOFTSERIAL + case IPL_SOFTNET: + return __SHIFTIN(XC_IPL_SOFTNET, XC_IPL_MASK); +#endif +#if IPL_SOFTBIO != IPL_SOFTNET + case IPL_SOFTBIO: + return __SHIFTIN(XC_IPL_SOFTBIO, XC_IPL_MASK); +#endif +#if IPL_SOFTCLOCK != IPL_SOFTBIO + case IPL_SOFTCLOCK: + return __SHIFTIN(XC_IPL_SOFTCLOCK, XC_IPL_MASK); +#endif + } + + panic("Invalid IPL: %d", ipl); +} + +/* + * Extract an XC_IPL from flags of xc_broadcast or xc_unicast. + */ +static inline unsigned int +xc_extract_ipl(unsigned int flags) +{ + + return __SHIFTOUT(flags, XC_IPL_MASK); +} + +/* * xc_init_cpu: * * Initialize the cross-call subsystem. Called once for each CPU @@ -176,13 +253,14 @@ xc_init_cpu(struct cpu_info *ci) * Trigger a call on all CPUs in the system. */ uint64_t -xc_broadcast(u_int flags, xcfunc_t func, void *arg1, void *arg2) +xc_broadcast(unsigned int flags, xcfunc_t func, void *arg1, void *arg2) { KASSERT(!cpu_intr_p() && !cpu_softintr_p()); if ((flags & XC_HIGHPRI) != 0) { - return xc_highpri(func, arg1, arg2, NULL); + int ipl = xc_extract_ipl(flags); + return xc_highpri(func, arg1, arg2, NULL, ipl); } else { return xc_lowpri(func, arg1, arg2, NULL); } @@ -194,7 +272,7 @@ xc_broadcast(u_int flags, xcfunc_t func, * Trigger a call on one CPU. */ uint64_t -xc_unicast(u_int flags, xcfunc_t func, void *arg1, void *arg2, +xc_unicast(unsigned int flags, xcfunc_t func, void *arg1, void *arg2, struct cpu_info *ci) { @@ -202,7 +280,8 @@ xc_unicast(u_int flags, xcfunc_t func, v KASSERT(!cpu_intr_p() && !cpu_softintr_p()); if ((flags & XC_HIGHPRI) != 0) { - return xc_highpri(func, arg1, arg2, ci); + int ipl = xc_extract_ipl(flags); + return xc_highpri(func, arg1, arg2, ci, ipl); } else { return xc_lowpri(func, arg1, arg2, ci); } @@ -329,8 +408,13 @@ xc_thread(void *cookie) void xc_ipi_handler(void) { + xc_state_t *xc = & xc_high_pri; + + KASSERT(xc->xc_ipl < __arraycount(xc_sihs)); + KASSERT(xc_sihs[xc->xc_ipl] != NULL); + /* Executes xc__highpri_intr() via software interrupt. */ - softint_schedule(xc_sih); + softint_schedule(xc_sihs[xc->xc_ipl]); } /* @@ -375,7 +459,8 @@ xc__highpri_intr(void *dummy) * 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_highpri(xcfunc_t func, void *arg1, void *arg2, struct cpu_info *ci, + unsigned int ipl) { xc_state_t *xc = &xc_high_pri; uint64_t where; @@ -388,6 +473,7 @@ xc_highpri(xcfunc_t func, void *arg1, vo xc->xc_arg1 = arg1; xc->xc_arg2 = arg2; xc->xc_headp += (ci ? 1 : ncpu); + xc->xc_ipl = ipl; where = xc->xc_headp; mutex_exit(&xc->xc_lock); Index: src/sys/sys/xcall.h diff -u src/sys/sys/xcall.h:1.5 src/sys/sys/xcall.h:1.5.30.1 --- src/sys/sys/xcall.h:1.5 Tue Feb 19 09:04:53 2013 +++ src/sys/sys/xcall.h Mon Feb 19 18:33:38 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: xcall.h,v 1.5 2013/02/19 09:04:53 martin Exp $ */ +/* $NetBSD: xcall.h,v 1.5.30.1 2018/02/19 18:33:38 snj Exp $ */ /*- * Copyright (c) 2007 The NetBSD Foundation, Inc. @@ -33,7 +33,8 @@ #define _SYS_XCALL_H_ #ifdef _KERNEL -#define XC_HIGHPRI 0x01 /* high priority */ +#define XC_HIGHPRI 0x01 /* high priority */ +#define XC_HIGHPRI_IPL(ipl) (XC_HIGHPRI | xc_encode_ipl(ipl)) typedef void (*xcfunc_t)(void *, void *); @@ -49,6 +50,8 @@ uint64_t xc_broadcast(u_int, xcfunc_t, v uint64_t xc_unicast(u_int, xcfunc_t, void *, void *, struct cpu_info *); void xc_wait(uint64_t); +unsigned int xc_encode_ipl(int); + #endif /* _KERNEL */ #endif /* _SYS_XCALL_H_ */