| 1 | /*	$OpenBSD: xcall.h,v 1.2 2025/11/10 12:34:52 dlg Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 2025 David Gwynne <dlg@openbsd.org> |
| 5 | * |
| 6 | * Permission to use, copy, modify, and distribute this software for any |
| 7 | * purpose with or without fee is hereby granted, provided that the above |
| 8 | * copyright notice and this permission notice appear in all copies. |
| 9 | * |
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 17 | */ |
| 18 | |
| 19 | /* |
| 20 | * CPU crosscall API |
| 21 | * |
| 22 | * Work to execute on a CPU is wrapped in a struct xcall, which is |
| 23 | * like a task or timeout. Each CPU (in an MP kernel) has an array |
| 24 | * of pointers to xcall structs. The local CPU uses CAS ops to try |
| 25 | * and swap their xcall onto one of the slots on the remote CPU, |
| 26 | * and will spin until space becomes available. Once the xcall has |
| 27 | * been added, an IPI is sent to the remote CPU to kick of processing |
| 28 | * of the array. The xcall IPI handler defers processing of the |
| 29 | * xcall array to a low IPL level using a softintr handler. |
| 30 | * |
| 31 | * To implement this API on an architecture requires the following: |
| 32 | * |
| 33 | * 1. A device has to depend on the xcall attribute to have the |
| 34 | * xcall code included in the kernel build. e.g., on amd64 the cpu |
| 35 | * device depends on the xcall attribute, as defined in |
| 36 | * src/sys/arch/amd64/conf/files.amd64: |
| 37 | * |
| 38 | * device cpu: xcall |
| 39 | * |
| 40 | * The rest of the changes are only necessary for MULTIPROCESSOR builds: |
| 41 | * |
| 42 | * 2. struct cpu_info has to have a `struct xcall_cpu ci_xcall` member. |
| 43 | * |
| 44 | * 3. cpu_xcall_establish has to be called against each cpu_info struct. |
| 45 | * |
| 46 | * 4. cpu_xcall_ipi has to be provided by machine/intr.h. |
| 47 | * |
| 48 | * 5. call cpu_xcall_dispatch at IPL_SOFTCLOCK on the target CPU. |
| 49 | */ |
| 50 | |
| 51 | #ifndef _SYS_XCALL_H |
| 52 | #define _SYS_XCALL_H |
| 53 | |
| 54 | struct xcall { |
| 55 | 	void (*xc_func)(void *); |
| 56 | 	void		*xc_arg; |
| 57 | }; |
| 58 | |
| 59 | /* MD code adds this to struct cpu_info as ci_xcall */ |
| 60 | struct xcall_cpu { |
| 61 | 	struct xcall	*xci_xcalls[4]; |
| 62 | 	void		*xci_softintr; |
| 63 | }; |
| 64 | |
| 65 | #ifdef _KERNEL |
| 66 | #define XCALL_INITIALIZER(_f, _a) {				\ |
| 67 | 	.xc_func = _f,						\ |
| 68 | 	.xc_arg = _a,						\ |
| 69 | } |
| 70 | |
| 71 | void	cpu_xcall_set(struct xcall *, void (*)(void *), void *); |
| 72 | void	cpu_xcall(struct cpu_info *, struct xcall *); |
| 73 | |
| 74 | void	cpu_xcall_sync(struct cpu_info *, void (*)(void *), void *, |
| 75 | 	 const char *); |
| 76 | |
| 77 | /* MD cpu setup calls this */ |
| 78 | void	cpu_xcall_establish(struct cpu_info *); |
| 79 | /* MD ipi handler calls this */ |
| 80 | void	cpu_xcall_dispatch(struct cpu_info *); |
| 81 | |
| 82 | #endif /* _KERNEL */ |
| 83 | |
| 84 | #endif /* _SYS_XCALL_H */ |