1*cbf5c65aSandvar /* $NetBSD: subr_interrupt.c,v 1.5 2021/12/10 20:36:04 andvar Exp $ */
2a604df28Sknakahara
3a604df28Sknakahara /*
4a604df28Sknakahara * Copyright (c) 2015 Internet Initiative Japan Inc.
5a604df28Sknakahara * All rights reserved.
6a604df28Sknakahara *
7a604df28Sknakahara * Redistribution and use in source and binary forms, with or without
8a604df28Sknakahara * modification, are permitted provided that the following conditions
9a604df28Sknakahara * are met:
10a604df28Sknakahara * 1. Redistributions of source code must retain the above copyright
11a604df28Sknakahara * notice, this list of conditions and the following disclaimer.
12a604df28Sknakahara * 2. Redistributions in binary form must reproduce the above copyright
13a604df28Sknakahara * notice, this list of conditions and the following disclaimer in the
14a604df28Sknakahara * documentation and/or other materials provided with the distribution.
15a604df28Sknakahara *
16a604df28Sknakahara * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17a604df28Sknakahara * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18a604df28Sknakahara * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19a604df28Sknakahara * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20a604df28Sknakahara * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21a604df28Sknakahara * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22a604df28Sknakahara * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23a604df28Sknakahara * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24a604df28Sknakahara * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25a604df28Sknakahara * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26a604df28Sknakahara * POSSIBILITY OF SUCH DAMAGE.
27a604df28Sknakahara */
28a604df28Sknakahara
29a604df28Sknakahara #include <sys/cdefs.h>
30*cbf5c65aSandvar __KERNEL_RCSID(0, "$NetBSD: subr_interrupt.c,v 1.5 2021/12/10 20:36:04 andvar Exp $");
31a604df28Sknakahara
32a604df28Sknakahara #include <sys/param.h>
33a604df28Sknakahara #include <sys/systm.h>
34a604df28Sknakahara #include <sys/kernel.h>
35a604df28Sknakahara #include <sys/errno.h>
36a604df28Sknakahara #include <sys/cpu.h>
37a604df28Sknakahara #include <sys/interrupt.h>
38a604df28Sknakahara #include <sys/intr.h>
39a604df28Sknakahara #include <sys/kcpuset.h>
40a604df28Sknakahara #include <sys/kmem.h>
41a604df28Sknakahara #include <sys/proc.h>
42a604df28Sknakahara #include <sys/xcall.h>
43a604df28Sknakahara #include <sys/sysctl.h>
44a604df28Sknakahara
45a604df28Sknakahara #include <sys/conf.h>
46a604df28Sknakahara #include <sys/intrio.h>
47a604df28Sknakahara #include <sys/kauth.h>
48a604df28Sknakahara
49a604df28Sknakahara #include <machine/limits.h>
50a604df28Sknakahara
51a604df28Sknakahara #ifdef INTR_DEBUG
52a604df28Sknakahara #define DPRINTF(msg) printf msg
53a604df28Sknakahara #else
54a604df28Sknakahara #define DPRINTF(msg)
55a604df28Sknakahara #endif
56a604df28Sknakahara
57a604df28Sknakahara static struct intrio_set kintrio_set = { "\0", NULL, 0 };
58a604df28Sknakahara
59a604df28Sknakahara #define UNSET_NOINTR_SHIELD 0
60a604df28Sknakahara #define SET_NOINTR_SHIELD 1
61a604df28Sknakahara
62a604df28Sknakahara static void
interrupt_shield_xcall(void * arg1,void * arg2)63a604df28Sknakahara interrupt_shield_xcall(void *arg1, void *arg2)
64a604df28Sknakahara {
65a604df28Sknakahara struct cpu_info *ci;
66a604df28Sknakahara struct schedstate_percpu *spc;
67a604df28Sknakahara int s, shield;
68a604df28Sknakahara
69a604df28Sknakahara ci = arg1;
70a604df28Sknakahara shield = (int)(intptr_t)arg2;
71a604df28Sknakahara spc = &ci->ci_schedstate;
72a604df28Sknakahara
73a604df28Sknakahara s = splsched();
74a604df28Sknakahara if (shield == UNSET_NOINTR_SHIELD)
75a604df28Sknakahara spc->spc_flags &= ~SPCF_NOINTR;
76a604df28Sknakahara else if (shield == SET_NOINTR_SHIELD)
77a604df28Sknakahara spc->spc_flags |= SPCF_NOINTR;
78a604df28Sknakahara splx(s);
79a604df28Sknakahara }
80a604df28Sknakahara
81a604df28Sknakahara /*
82a604df28Sknakahara * Change SPCF_NOINTR flag of schedstate_percpu->spc_flags.
83a604df28Sknakahara */
84a604df28Sknakahara static int
interrupt_shield(u_int cpu_idx,int shield)85a604df28Sknakahara interrupt_shield(u_int cpu_idx, int shield)
86a604df28Sknakahara {
87a604df28Sknakahara struct cpu_info *ci;
88a604df28Sknakahara struct schedstate_percpu *spc;
89a604df28Sknakahara
90a604df28Sknakahara KASSERT(mutex_owned(&cpu_lock));
91a604df28Sknakahara
92a604df28Sknakahara ci = cpu_lookup(cpu_idx);
93a604df28Sknakahara if (ci == NULL)
94a604df28Sknakahara return EINVAL;
95a604df28Sknakahara
96a604df28Sknakahara spc = &ci->ci_schedstate;
97a604df28Sknakahara if (shield == UNSET_NOINTR_SHIELD) {
98a604df28Sknakahara if ((spc->spc_flags & SPCF_NOINTR) == 0)
99a604df28Sknakahara return 0;
100a604df28Sknakahara } else if (shield == SET_NOINTR_SHIELD) {
101a604df28Sknakahara if ((spc->spc_flags & SPCF_NOINTR) != 0)
102a604df28Sknakahara return 0;
103a604df28Sknakahara }
104a604df28Sknakahara
105a604df28Sknakahara if (ci == curcpu() || !mp_online) {
106a604df28Sknakahara interrupt_shield_xcall(ci, (void *)(intptr_t)shield);
107a604df28Sknakahara } else {
108a604df28Sknakahara uint64_t where;
109a604df28Sknakahara where = xc_unicast(0, interrupt_shield_xcall, ci,
110a604df28Sknakahara (void *)(intptr_t)shield, ci);
111a604df28Sknakahara xc_wait(where);
112a604df28Sknakahara }
113a604df28Sknakahara
114a604df28Sknakahara spc->spc_lastmod = time_second;
115a604df28Sknakahara return 0;
116a604df28Sknakahara }
117a604df28Sknakahara
118a604df28Sknakahara /*
119a604df28Sknakahara * Move all assigned interrupts from "cpu_idx" to the other cpu as possible.
120a604df28Sknakahara * The destination cpu is the lowest cpuid of available cpus.
121a604df28Sknakahara * If there are no available cpus, give up to move interrupts.
122a604df28Sknakahara */
123a604df28Sknakahara static int
interrupt_avert_intr(u_int cpu_idx)124a604df28Sknakahara interrupt_avert_intr(u_int cpu_idx)
125a604df28Sknakahara {
126a604df28Sknakahara kcpuset_t *cpuset;
127a604df28Sknakahara struct intrids_handler *ii_handler;
128a604df28Sknakahara intrid_t *ids;
129c14455feSreinoud int error = 0, i, nids;
130a604df28Sknakahara
131a604df28Sknakahara kcpuset_create(&cpuset, true);
132a604df28Sknakahara kcpuset_set(cpuset, cpu_idx);
133a604df28Sknakahara
134a604df28Sknakahara ii_handler = interrupt_construct_intrids(cpuset);
135a604df28Sknakahara if (ii_handler == NULL) {
13696bd66bcSchristos error = EINVAL;
137a604df28Sknakahara goto out;
138a604df28Sknakahara }
139a604df28Sknakahara nids = ii_handler->iih_nids;
140a604df28Sknakahara if (nids == 0) {
141a604df28Sknakahara error = 0;
142a604df28Sknakahara goto destruct_out;
143a604df28Sknakahara }
144a604df28Sknakahara
145a604df28Sknakahara interrupt_get_available(cpuset);
146a604df28Sknakahara kcpuset_clear(cpuset, cpu_idx);
147a604df28Sknakahara if (kcpuset_iszero(cpuset)) {
148a604df28Sknakahara DPRINTF(("%s: no available cpu\n", __func__));
149a604df28Sknakahara error = ENOENT;
150a604df28Sknakahara goto destruct_out;
151a604df28Sknakahara }
152a604df28Sknakahara
153a604df28Sknakahara ids = ii_handler->iih_intrids;
154a604df28Sknakahara for (i = 0; i < nids; i++) {
155a604df28Sknakahara error = interrupt_distribute_handler(ids[i], cpuset, NULL);
156a604df28Sknakahara if (error)
157a604df28Sknakahara break;
158a604df28Sknakahara }
159a604df28Sknakahara
160a604df28Sknakahara destruct_out:
161a604df28Sknakahara interrupt_destruct_intrids(ii_handler);
162a604df28Sknakahara out:
163a604df28Sknakahara kcpuset_destroy(cpuset);
164a604df28Sknakahara return error;
165a604df28Sknakahara }
166a604df28Sknakahara
167a604df28Sknakahara /*
168a604df28Sknakahara * Return actual intrio_list_line size.
169a604df28Sknakahara * intrio_list_line size is variable by ncpu.
170a604df28Sknakahara */
171a604df28Sknakahara static size_t
interrupt_intrio_list_line_size(void)172a604df28Sknakahara interrupt_intrio_list_line_size(void)
173a604df28Sknakahara {
174a604df28Sknakahara
175a604df28Sknakahara return sizeof(struct intrio_list_line) +
176a604df28Sknakahara sizeof(struct intrio_list_line_cpu) * (ncpu - 1);
177a604df28Sknakahara }
178a604df28Sknakahara
179a604df28Sknakahara /*
180a604df28Sknakahara * Return the size of interrupts list data on success.
181a604df28Sknakahara * Reterun 0 on failed.
182a604df28Sknakahara */
18396bd66bcSchristos static int
interrupt_intrio_list_size(size_t * ilsize)18496bd66bcSchristos interrupt_intrio_list_size(size_t *ilsize)
185a604df28Sknakahara {
186a604df28Sknakahara struct intrids_handler *ii_handler;
187a604df28Sknakahara
18896bd66bcSchristos *ilsize = 0;
189a604df28Sknakahara
190a604df28Sknakahara /* buffer header */
19196bd66bcSchristos *ilsize += sizeof(struct intrio_list);
192a604df28Sknakahara
193a604df28Sknakahara /* il_line body */
194a604df28Sknakahara ii_handler = interrupt_construct_intrids(kcpuset_running);
195a604df28Sknakahara if (ii_handler == NULL)
19696bd66bcSchristos return EOPNOTSUPP;
19796bd66bcSchristos *ilsize += interrupt_intrio_list_line_size() * ii_handler->iih_nids;
198a604df28Sknakahara
199a604df28Sknakahara interrupt_destruct_intrids(ii_handler);
20096bd66bcSchristos return 0;
201a604df28Sknakahara }
202a604df28Sknakahara
203a604df28Sknakahara /*
204a604df28Sknakahara * Set intrctl list data to "il", and return list structure bytes.
205*cbf5c65aSandvar * If error occurred, return <0.
206a604df28Sknakahara * If "data" == NULL, simply return list structure bytes.
207a604df28Sknakahara */
208a604df28Sknakahara static int
interrupt_intrio_list(struct intrio_list * il,size_t ilsize)20996bd66bcSchristos interrupt_intrio_list(struct intrio_list *il, size_t ilsize)
210a604df28Sknakahara {
211a604df28Sknakahara struct intrio_list_line *illine;
212a604df28Sknakahara kcpuset_t *assigned, *avail;
213a604df28Sknakahara struct intrids_handler *ii_handler;
214a604df28Sknakahara intrid_t *ids;
215a604df28Sknakahara u_int cpu_idx;
21696bd66bcSchristos int nids, intr_idx, error, line_size;
217a604df28Sknakahara
218a604df28Sknakahara illine = (struct intrio_list_line *)
219a604df28Sknakahara ((char *)il + sizeof(struct intrio_list));
220a604df28Sknakahara il->il_lineoffset = (off_t)((uintptr_t)illine - (uintptr_t)il);
221a604df28Sknakahara
222a604df28Sknakahara kcpuset_create(&avail, true);
223a604df28Sknakahara interrupt_get_available(avail);
224a604df28Sknakahara kcpuset_create(&assigned, true);
225a604df28Sknakahara
226a604df28Sknakahara ii_handler = interrupt_construct_intrids(kcpuset_running);
227a604df28Sknakahara if (ii_handler == NULL) {
228a604df28Sknakahara DPRINTF(("%s: interrupt_construct_intrids() failed\n",
229a604df28Sknakahara __func__));
23096bd66bcSchristos error = EOPNOTSUPP;
231a604df28Sknakahara goto out;
232a604df28Sknakahara }
233a604df28Sknakahara
234a604df28Sknakahara line_size = interrupt_intrio_list_line_size();
23596bd66bcSchristos /* ensure interrupts are not added after interrupt_intrio_list_size() */
236a604df28Sknakahara nids = ii_handler->iih_nids;
237a604df28Sknakahara ids = ii_handler->iih_intrids;
238a604df28Sknakahara if (ilsize < sizeof(struct intrio_list) + line_size * nids) {
239a604df28Sknakahara DPRINTF(("%s: interrupts are added during execution.\n",
240a604df28Sknakahara __func__));
24196bd66bcSchristos error = EAGAIN;
242a604df28Sknakahara goto destruct_out;
243a604df28Sknakahara }
244a604df28Sknakahara
245a604df28Sknakahara for (intr_idx = 0; intr_idx < nids; intr_idx++) {
246a604df28Sknakahara char devname[INTRDEVNAMEBUF];
247a604df28Sknakahara
248a604df28Sknakahara strncpy(illine->ill_intrid, ids[intr_idx], INTRIDBUF);
249a604df28Sknakahara interrupt_get_devname(ids[intr_idx], devname, sizeof(devname));
250a604df28Sknakahara strncpy(illine->ill_xname, devname, INTRDEVNAMEBUF);
251a604df28Sknakahara
252a604df28Sknakahara interrupt_get_assigned(ids[intr_idx], assigned);
253a604df28Sknakahara for (cpu_idx = 0; cpu_idx < ncpu; cpu_idx++) {
254a604df28Sknakahara struct intrio_list_line_cpu *illcpu =
255a604df28Sknakahara &illine->ill_cpu[cpu_idx];
256a604df28Sknakahara
257a604df28Sknakahara illcpu->illc_assigned =
25896bd66bcSchristos kcpuset_isset(assigned, cpu_idx);
259a604df28Sknakahara illcpu->illc_count =
260a604df28Sknakahara interrupt_get_count(ids[intr_idx], cpu_idx);
261a604df28Sknakahara }
262a604df28Sknakahara
263a604df28Sknakahara illine = (struct intrio_list_line *)
264a604df28Sknakahara ((char *)illine + line_size);
265a604df28Sknakahara }
266a604df28Sknakahara
26796bd66bcSchristos error = 0;
268a604df28Sknakahara il->il_version = INTRIO_LIST_VERSION;
269a604df28Sknakahara il->il_ncpus = ncpu;
270a604df28Sknakahara il->il_nintrs = nids;
271a604df28Sknakahara il->il_linesize = line_size;
272a604df28Sknakahara il->il_bufsize = ilsize;
273a604df28Sknakahara
274a604df28Sknakahara destruct_out:
275a604df28Sknakahara interrupt_destruct_intrids(ii_handler);
276a604df28Sknakahara out:
277a604df28Sknakahara kcpuset_destroy(assigned);
278a604df28Sknakahara kcpuset_destroy(avail);
279a604df28Sknakahara
28096bd66bcSchristos return error;
281a604df28Sknakahara }
282a604df28Sknakahara
283a604df28Sknakahara /*
284a604df28Sknakahara * "intrctl list" entry
285a604df28Sknakahara */
286a604df28Sknakahara static int
interrupt_intrio_list_sysctl(SYSCTLFN_ARGS)287a604df28Sknakahara interrupt_intrio_list_sysctl(SYSCTLFN_ARGS)
288a604df28Sknakahara {
28996bd66bcSchristos int error;
290a604df28Sknakahara void *buf;
29196bd66bcSchristos size_t ilsize;
292a604df28Sknakahara
293a604df28Sknakahara if (oldlenp == NULL)
294a604df28Sknakahara return EINVAL;
295a604df28Sknakahara
29696bd66bcSchristos if ((error = interrupt_intrio_list_size(&ilsize)) != 0)
29796bd66bcSchristos return error;
29896bd66bcSchristos
299a604df28Sknakahara /*
300a604df28Sknakahara * If oldp == NULL, the sysctl(8) caller process want to get the size of
301a604df28Sknakahara * intrctl list data only.
302a604df28Sknakahara */
303a604df28Sknakahara if (oldp == NULL) {
30496bd66bcSchristos *oldlenp = ilsize;
305a604df28Sknakahara return 0;
306a604df28Sknakahara }
307a604df28Sknakahara
308a604df28Sknakahara /*
30996bd66bcSchristos * If oldp != NULL, the sysctl(8) caller process want to get both the
31096bd66bcSchristos * size and the contents of intrctl list data.
311a604df28Sknakahara */
31296bd66bcSchristos if (*oldlenp < ilsize)
313a604df28Sknakahara return ENOMEM;
314a604df28Sknakahara
31596bd66bcSchristos buf = kmem_zalloc(ilsize, KM_SLEEP);
31696bd66bcSchristos if ((error = interrupt_intrio_list(buf, ilsize)) != 0)
317a604df28Sknakahara goto out;
318a604df28Sknakahara
31996bd66bcSchristos error = copyout(buf, oldp, ilsize);
320a604df28Sknakahara out:
32196bd66bcSchristos kmem_free(buf, ilsize);
322a604df28Sknakahara return error;
323a604df28Sknakahara }
324a604df28Sknakahara
325a604df28Sknakahara /*
326a604df28Sknakahara * "intrctl affinity" entry
327a604df28Sknakahara */
328a604df28Sknakahara static int
interrupt_set_affinity_sysctl(SYSCTLFN_ARGS)329a604df28Sknakahara interrupt_set_affinity_sysctl(SYSCTLFN_ARGS)
330a604df28Sknakahara {
331a604df28Sknakahara struct sysctlnode node;
332a604df28Sknakahara struct intrio_set *iset;
333a604df28Sknakahara cpuset_t *ucpuset;
334a604df28Sknakahara kcpuset_t *kcpuset;
335a604df28Sknakahara int error;
336a604df28Sknakahara
337a604df28Sknakahara error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_INTR,
338a604df28Sknakahara KAUTH_REQ_SYSTEM_INTR_AFFINITY, NULL, NULL, NULL);
339a604df28Sknakahara if (error)
340a604df28Sknakahara return EPERM;
341a604df28Sknakahara
342a604df28Sknakahara node = *rnode;
343a604df28Sknakahara iset = (struct intrio_set *)node.sysctl_data;
344a604df28Sknakahara
345a604df28Sknakahara error = sysctl_lookup(SYSCTLFN_CALL(&node));
346a604df28Sknakahara if (error != 0 || newp == NULL)
347a604df28Sknakahara return error;
348a604df28Sknakahara
349a604df28Sknakahara ucpuset = iset->cpuset;
350a604df28Sknakahara kcpuset_create(&kcpuset, true);
351a604df28Sknakahara error = kcpuset_copyin(ucpuset, kcpuset, iset->cpuset_size);
352a604df28Sknakahara if (error)
353a604df28Sknakahara goto out;
354a604df28Sknakahara if (kcpuset_iszero(kcpuset)) {
355a604df28Sknakahara error = EINVAL;
356a604df28Sknakahara goto out;
357a604df28Sknakahara }
358a604df28Sknakahara
359a604df28Sknakahara error = interrupt_distribute_handler(iset->intrid, kcpuset, NULL);
360a604df28Sknakahara
361a604df28Sknakahara out:
362a604df28Sknakahara kcpuset_destroy(kcpuset);
363a604df28Sknakahara return error;
364a604df28Sknakahara }
365a604df28Sknakahara
366a604df28Sknakahara /*
367a604df28Sknakahara * "intrctl intr" entry
368a604df28Sknakahara */
369a604df28Sknakahara static int
interrupt_intr_sysctl(SYSCTLFN_ARGS)370a604df28Sknakahara interrupt_intr_sysctl(SYSCTLFN_ARGS)
371a604df28Sknakahara {
372a604df28Sknakahara struct sysctlnode node;
373a604df28Sknakahara struct intrio_set *iset;
374a604df28Sknakahara cpuset_t *ucpuset;
375a604df28Sknakahara kcpuset_t *kcpuset;
376a604df28Sknakahara int error;
377a604df28Sknakahara u_int cpu_idx;
378a604df28Sknakahara
379a604df28Sknakahara error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CPU,
380a604df28Sknakahara KAUTH_REQ_SYSTEM_CPU_SETSTATE, NULL, NULL, NULL);
381a604df28Sknakahara if (error)
382a604df28Sknakahara return EPERM;
383a604df28Sknakahara
384a604df28Sknakahara node = *rnode;
385a604df28Sknakahara iset = (struct intrio_set *)node.sysctl_data;
386a604df28Sknakahara
387a604df28Sknakahara error = sysctl_lookup(SYSCTLFN_CALL(&node));
388a604df28Sknakahara if (error != 0 || newp == NULL)
389a604df28Sknakahara return error;
390a604df28Sknakahara
391a604df28Sknakahara ucpuset = iset->cpuset;
392a604df28Sknakahara kcpuset_create(&kcpuset, true);
393a604df28Sknakahara error = kcpuset_copyin(ucpuset, kcpuset, iset->cpuset_size);
394a604df28Sknakahara if (error)
395a604df28Sknakahara goto out;
396a604df28Sknakahara if (kcpuset_iszero(kcpuset)) {
397a604df28Sknakahara error = EINVAL;
398a604df28Sknakahara goto out;
399a604df28Sknakahara }
400a604df28Sknakahara
401a604df28Sknakahara cpu_idx = kcpuset_ffs(kcpuset) - 1; /* support one CPU only */
402a604df28Sknakahara
403a604df28Sknakahara mutex_enter(&cpu_lock);
404a604df28Sknakahara error = interrupt_shield(cpu_idx, UNSET_NOINTR_SHIELD);
405a604df28Sknakahara mutex_exit(&cpu_lock);
406a604df28Sknakahara
407a604df28Sknakahara out:
408a604df28Sknakahara kcpuset_destroy(kcpuset);
409a604df28Sknakahara return error;
410a604df28Sknakahara }
411a604df28Sknakahara
412a604df28Sknakahara /*
413a604df28Sknakahara * "intrctl nointr" entry
414a604df28Sknakahara */
415a604df28Sknakahara static int
interrupt_nointr_sysctl(SYSCTLFN_ARGS)416a604df28Sknakahara interrupt_nointr_sysctl(SYSCTLFN_ARGS)
417a604df28Sknakahara {
418a604df28Sknakahara struct sysctlnode node;
419a604df28Sknakahara struct intrio_set *iset;
420a604df28Sknakahara cpuset_t *ucpuset;
421a604df28Sknakahara kcpuset_t *kcpuset;
422a604df28Sknakahara int error;
423a604df28Sknakahara u_int cpu_idx;
424a604df28Sknakahara
425a604df28Sknakahara error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CPU,
426a604df28Sknakahara KAUTH_REQ_SYSTEM_CPU_SETSTATE, NULL, NULL, NULL);
427a604df28Sknakahara if (error)
428a604df28Sknakahara return EPERM;
429a604df28Sknakahara
430a604df28Sknakahara node = *rnode;
431a604df28Sknakahara iset = (struct intrio_set *)node.sysctl_data;
432a604df28Sknakahara
433a604df28Sknakahara error = sysctl_lookup(SYSCTLFN_CALL(&node));
434a604df28Sknakahara if (error != 0 || newp == NULL)
435a604df28Sknakahara return error;
436a604df28Sknakahara
437a604df28Sknakahara ucpuset = iset->cpuset;
438a604df28Sknakahara kcpuset_create(&kcpuset, true);
439a604df28Sknakahara error = kcpuset_copyin(ucpuset, kcpuset, iset->cpuset_size);
440a604df28Sknakahara if (error)
441a604df28Sknakahara goto out;
442a604df28Sknakahara if (kcpuset_iszero(kcpuset)) {
443a604df28Sknakahara error = EINVAL;
444a604df28Sknakahara goto out;
445a604df28Sknakahara }
446a604df28Sknakahara
447a604df28Sknakahara cpu_idx = kcpuset_ffs(kcpuset) - 1; /* support one CPU only */
448a604df28Sknakahara
449a604df28Sknakahara mutex_enter(&cpu_lock);
450a604df28Sknakahara error = interrupt_shield(cpu_idx, SET_NOINTR_SHIELD);
451a604df28Sknakahara mutex_exit(&cpu_lock);
452a604df28Sknakahara if (error)
453a604df28Sknakahara goto out;
454a604df28Sknakahara
455a604df28Sknakahara error = interrupt_avert_intr(cpu_idx);
456a604df28Sknakahara
457a604df28Sknakahara out:
458a604df28Sknakahara kcpuset_destroy(kcpuset);
459a604df28Sknakahara return error;
460a604df28Sknakahara }
461a604df28Sknakahara
462a604df28Sknakahara SYSCTL_SETUP(sysctl_interrupt_setup, "sysctl interrupt setup")
463a604df28Sknakahara {
464a604df28Sknakahara const struct sysctlnode *node = NULL;
465a604df28Sknakahara
466a604df28Sknakahara sysctl_createv(clog, 0, NULL, &node,
467a604df28Sknakahara CTLFLAG_PERMANENT, CTLTYPE_NODE,
468a604df28Sknakahara "intr", SYSCTL_DESCR("Interrupt options"),
469a604df28Sknakahara NULL, 0, NULL, 0,
470a604df28Sknakahara CTL_KERN, CTL_CREATE, CTL_EOL);
471a604df28Sknakahara
472a604df28Sknakahara sysctl_createv(clog, 0, &node, NULL,
473a604df28Sknakahara CTLFLAG_PERMANENT, CTLTYPE_STRUCT,
474a604df28Sknakahara "list", SYSCTL_DESCR("intrctl list"),
475a604df28Sknakahara interrupt_intrio_list_sysctl, 0, NULL,
476a604df28Sknakahara 0, CTL_CREATE, CTL_EOL);
477a604df28Sknakahara
478a604df28Sknakahara sysctl_createv(clog, 0, &node, NULL,
479a604df28Sknakahara CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_STRUCT,
480a604df28Sknakahara "affinity", SYSCTL_DESCR("set affinity"),
481a604df28Sknakahara interrupt_set_affinity_sysctl, 0, &kintrio_set,
482a604df28Sknakahara sizeof(kintrio_set), CTL_CREATE, CTL_EOL);
483a604df28Sknakahara
484a604df28Sknakahara sysctl_createv(clog, 0, &node, NULL,
485a604df28Sknakahara CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_STRUCT,
486a604df28Sknakahara "intr", SYSCTL_DESCR("set intr"),
487a604df28Sknakahara interrupt_intr_sysctl, 0, &kintrio_set,
488a604df28Sknakahara sizeof(kintrio_set), CTL_CREATE, CTL_EOL);
489a604df28Sknakahara
490a604df28Sknakahara sysctl_createv(clog, 0, &node, NULL,
491a604df28Sknakahara CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_STRUCT,
492a604df28Sknakahara "nointr", SYSCTL_DESCR("set nointr"),
493a604df28Sknakahara interrupt_nointr_sysctl, 0, &kintrio_set,
494a604df28Sknakahara sizeof(kintrio_set), CTL_CREATE, CTL_EOL);
495a604df28Sknakahara }
496