subr_percpu.c revision 1.25 1 1.25 riastrad /* $NetBSD: subr_percpu.c,v 1.25 2020/05/11 21:37:31 riastradh Exp $ */
2 1.1 yamt
3 1.1 yamt /*-
4 1.1 yamt * Copyright (c)2007,2008 YAMAMOTO Takashi,
5 1.1 yamt * All rights reserved.
6 1.1 yamt *
7 1.1 yamt * Redistribution and use in source and binary forms, with or without
8 1.1 yamt * modification, are permitted provided that the following conditions
9 1.1 yamt * are met:
10 1.1 yamt * 1. Redistributions of source code must retain the above copyright
11 1.1 yamt * notice, this list of conditions and the following disclaimer.
12 1.1 yamt * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 yamt * notice, this list of conditions and the following disclaimer in the
14 1.1 yamt * documentation and/or other materials provided with the distribution.
15 1.1 yamt *
16 1.1 yamt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 1.1 yamt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1 yamt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1 yamt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 1.1 yamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1 yamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1 yamt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 yamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1 yamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 yamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 yamt * SUCH DAMAGE.
27 1.1 yamt */
28 1.1 yamt
29 1.1 yamt /*
30 1.1 yamt * per-cpu storage.
31 1.1 yamt */
32 1.1 yamt
33 1.1 yamt #include <sys/cdefs.h>
34 1.25 riastrad __KERNEL_RCSID(0, "$NetBSD: subr_percpu.c,v 1.25 2020/05/11 21:37:31 riastradh Exp $");
35 1.1 yamt
36 1.1 yamt #include <sys/param.h>
37 1.1 yamt #include <sys/cpu.h>
38 1.23 riastrad #include <sys/kernel.h>
39 1.1 yamt #include <sys/kmem.h>
40 1.1 yamt #include <sys/mutex.h>
41 1.1 yamt #include <sys/percpu.h>
42 1.1 yamt #include <sys/rwlock.h>
43 1.1 yamt #include <sys/vmem.h>
44 1.1 yamt #include <sys/xcall.h>
45 1.1 yamt
46 1.1 yamt #define PERCPU_QUANTUM_SIZE (ALIGNBYTES + 1)
47 1.1 yamt #define PERCPU_QCACHE_MAX 0
48 1.1 yamt #define PERCPU_IMPORT_SIZE 2048
49 1.1 yamt
50 1.21 riastrad struct percpu {
51 1.21 riastrad unsigned pc_offset;
52 1.21 riastrad size_t pc_size;
53 1.25 riastrad percpu_callback_t pc_ctor;
54 1.21 riastrad percpu_callback_t pc_dtor;
55 1.21 riastrad void *pc_cookie;
56 1.25 riastrad LIST_ENTRY(percpu) pc_list;
57 1.21 riastrad };
58 1.8 yamt
59 1.13 rmind static krwlock_t percpu_swap_lock __cacheline_aligned;
60 1.22 riastrad static vmem_t * percpu_offset_arena __read_mostly;
61 1.22 riastrad static struct {
62 1.22 riastrad kmutex_t lock;
63 1.22 riastrad unsigned int nextoff;
64 1.25 riastrad LIST_HEAD(, percpu) ctor_list;
65 1.25 riastrad struct lwp *busy;
66 1.25 riastrad kcondvar_t cv;
67 1.22 riastrad } percpu_allocation __cacheline_aligned;
68 1.9 ad
69 1.1 yamt static percpu_cpu_t *
70 1.1 yamt cpu_percpu(struct cpu_info *ci)
71 1.1 yamt {
72 1.1 yamt
73 1.1 yamt return &ci->ci_data.cpu_percpu;
74 1.1 yamt }
75 1.1 yamt
76 1.1 yamt static unsigned int
77 1.1 yamt percpu_offset(percpu_t *pc)
78 1.1 yamt {
79 1.21 riastrad const unsigned int off = pc->pc_offset;
80 1.1 yamt
81 1.22 riastrad KASSERT(off < percpu_allocation.nextoff);
82 1.8 yamt return off;
83 1.1 yamt }
84 1.1 yamt
85 1.1 yamt /*
86 1.1 yamt * percpu_cpu_swap: crosscall handler for percpu_cpu_enlarge
87 1.1 yamt */
88 1.19 kamil __noubsan
89 1.1 yamt static void
90 1.1 yamt percpu_cpu_swap(void *p1, void *p2)
91 1.1 yamt {
92 1.1 yamt struct cpu_info * const ci = p1;
93 1.1 yamt percpu_cpu_t * const newpcc = p2;
94 1.1 yamt percpu_cpu_t * const pcc = cpu_percpu(ci);
95 1.1 yamt
96 1.12 martin KASSERT(ci == curcpu() || !mp_online);
97 1.11 matt
98 1.1 yamt /*
99 1.1 yamt * swap *pcc and *newpcc unless anyone has beaten us.
100 1.1 yamt */
101 1.1 yamt rw_enter(&percpu_swap_lock, RW_WRITER);
102 1.1 yamt if (newpcc->pcc_size > pcc->pcc_size) {
103 1.1 yamt percpu_cpu_t tmp;
104 1.1 yamt int s;
105 1.1 yamt
106 1.1 yamt tmp = *pcc;
107 1.1 yamt
108 1.1 yamt /*
109 1.1 yamt * block interrupts so that we don't lose their modifications.
110 1.1 yamt */
111 1.1 yamt
112 1.1 yamt s = splhigh();
113 1.1 yamt
114 1.1 yamt /*
115 1.1 yamt * copy data to new storage.
116 1.1 yamt */
117 1.1 yamt
118 1.1 yamt memcpy(newpcc->pcc_data, pcc->pcc_data, pcc->pcc_size);
119 1.1 yamt
120 1.1 yamt /*
121 1.1 yamt * this assignment needs to be atomic for percpu_getptr_remote.
122 1.1 yamt */
123 1.1 yamt
124 1.1 yamt pcc->pcc_data = newpcc->pcc_data;
125 1.1 yamt
126 1.1 yamt splx(s);
127 1.1 yamt
128 1.1 yamt pcc->pcc_size = newpcc->pcc_size;
129 1.1 yamt *newpcc = tmp;
130 1.1 yamt }
131 1.1 yamt rw_exit(&percpu_swap_lock);
132 1.1 yamt }
133 1.1 yamt
134 1.1 yamt /*
135 1.1 yamt * percpu_cpu_enlarge: ensure that percpu_cpu_t of each cpus have enough space
136 1.1 yamt */
137 1.1 yamt
138 1.1 yamt static void
139 1.1 yamt percpu_cpu_enlarge(size_t size)
140 1.1 yamt {
141 1.1 yamt CPU_INFO_ITERATOR cii;
142 1.1 yamt struct cpu_info *ci;
143 1.1 yamt
144 1.1 yamt for (CPU_INFO_FOREACH(cii, ci)) {
145 1.1 yamt percpu_cpu_t pcc;
146 1.1 yamt
147 1.1 yamt pcc.pcc_data = kmem_alloc(size, KM_SLEEP); /* XXX cacheline */
148 1.1 yamt pcc.pcc_size = size;
149 1.1 yamt if (!mp_online) {
150 1.1 yamt percpu_cpu_swap(ci, &pcc);
151 1.1 yamt } else {
152 1.1 yamt uint64_t where;
153 1.1 yamt
154 1.1 yamt where = xc_unicast(0, percpu_cpu_swap, ci, &pcc, ci);
155 1.1 yamt xc_wait(where);
156 1.1 yamt }
157 1.20 riastrad KASSERT(pcc.pcc_size <= size);
158 1.1 yamt if (pcc.pcc_data != NULL) {
159 1.1 yamt kmem_free(pcc.pcc_data, pcc.pcc_size);
160 1.1 yamt }
161 1.1 yamt }
162 1.1 yamt }
163 1.1 yamt
164 1.1 yamt /*
165 1.1 yamt * percpu_backend_alloc: vmem import callback for percpu_offset_arena
166 1.1 yamt */
167 1.1 yamt
168 1.15 dyoung static int
169 1.16 para percpu_backend_alloc(vmem_t *dummy, vmem_size_t size, vmem_size_t *resultsize,
170 1.15 dyoung vm_flag_t vmflags, vmem_addr_t *addrp)
171 1.1 yamt {
172 1.1 yamt unsigned int offset;
173 1.1 yamt unsigned int nextoff;
174 1.1 yamt
175 1.3 yamt ASSERT_SLEEPABLE();
176 1.1 yamt KASSERT(dummy == NULL);
177 1.1 yamt
178 1.1 yamt if ((vmflags & VM_NOSLEEP) != 0)
179 1.15 dyoung return ENOMEM;
180 1.1 yamt
181 1.1 yamt size = roundup(size, PERCPU_IMPORT_SIZE);
182 1.22 riastrad mutex_enter(&percpu_allocation.lock);
183 1.22 riastrad offset = percpu_allocation.nextoff;
184 1.22 riastrad percpu_allocation.nextoff = nextoff = percpu_allocation.nextoff + size;
185 1.22 riastrad mutex_exit(&percpu_allocation.lock);
186 1.1 yamt
187 1.1 yamt percpu_cpu_enlarge(nextoff);
188 1.1 yamt
189 1.1 yamt *resultsize = size;
190 1.15 dyoung *addrp = (vmem_addr_t)offset;
191 1.15 dyoung return 0;
192 1.1 yamt }
193 1.1 yamt
194 1.2 yamt static void
195 1.2 yamt percpu_zero_cb(void *vp, void *vp2, struct cpu_info *ci)
196 1.2 yamt {
197 1.2 yamt size_t sz = (uintptr_t)vp2;
198 1.2 yamt
199 1.2 yamt memset(vp, 0, sz);
200 1.2 yamt }
201 1.2 yamt
202 1.2 yamt /*
203 1.2 yamt * percpu_zero: initialize percpu storage with zero.
204 1.2 yamt */
205 1.2 yamt
206 1.2 yamt static void
207 1.2 yamt percpu_zero(percpu_t *pc, size_t sz)
208 1.2 yamt {
209 1.2 yamt
210 1.2 yamt percpu_foreach(pc, percpu_zero_cb, (void *)(uintptr_t)sz);
211 1.2 yamt }
212 1.2 yamt
213 1.1 yamt /*
214 1.1 yamt * percpu_init: subsystem initialization
215 1.1 yamt */
216 1.1 yamt
217 1.1 yamt void
218 1.1 yamt percpu_init(void)
219 1.1 yamt {
220 1.1 yamt
221 1.3 yamt ASSERT_SLEEPABLE();
222 1.1 yamt rw_init(&percpu_swap_lock);
223 1.22 riastrad mutex_init(&percpu_allocation.lock, MUTEX_DEFAULT, IPL_NONE);
224 1.22 riastrad percpu_allocation.nextoff = PERCPU_QUANTUM_SIZE;
225 1.25 riastrad LIST_INIT(&percpu_allocation.ctor_list);
226 1.25 riastrad percpu_allocation.busy = NULL;
227 1.25 riastrad cv_init(&percpu_allocation.cv, "percpu");
228 1.1 yamt
229 1.16 para percpu_offset_arena = vmem_xcreate("percpu", 0, 0, PERCPU_QUANTUM_SIZE,
230 1.1 yamt percpu_backend_alloc, NULL, NULL, PERCPU_QCACHE_MAX, VM_SLEEP,
231 1.1 yamt IPL_NONE);
232 1.1 yamt }
233 1.1 yamt
234 1.1 yamt /*
235 1.1 yamt * percpu_init_cpu: cpu initialization
236 1.1 yamt *
237 1.1 yamt * => should be called before the cpu appears on the list for CPU_INFO_FOREACH.
238 1.25 riastrad * => may be called for static CPUs afterward (typically just primary CPU)
239 1.1 yamt */
240 1.1 yamt
241 1.1 yamt void
242 1.1 yamt percpu_init_cpu(struct cpu_info *ci)
243 1.1 yamt {
244 1.1 yamt percpu_cpu_t * const pcc = cpu_percpu(ci);
245 1.25 riastrad struct percpu *pc;
246 1.22 riastrad size_t size = percpu_allocation.nextoff; /* XXX racy */
247 1.1 yamt
248 1.3 yamt ASSERT_SLEEPABLE();
249 1.25 riastrad
250 1.25 riastrad /*
251 1.25 riastrad * For the primary CPU, prior percpu_create may have already
252 1.25 riastrad * triggered allocation, so there's nothing more for us to do
253 1.25 riastrad * here.
254 1.25 riastrad */
255 1.25 riastrad if (pcc->pcc_size)
256 1.25 riastrad return;
257 1.25 riastrad KASSERT(pcc->pcc_data == NULL);
258 1.25 riastrad
259 1.25 riastrad /*
260 1.25 riastrad * Otherwise, allocate storage and, while the constructor list
261 1.25 riastrad * is locked, run constructors for all percpus on this CPU.
262 1.25 riastrad */
263 1.1 yamt pcc->pcc_size = size;
264 1.1 yamt if (size) {
265 1.1 yamt pcc->pcc_data = kmem_zalloc(pcc->pcc_size, KM_SLEEP);
266 1.25 riastrad mutex_enter(&percpu_allocation.lock);
267 1.25 riastrad while (percpu_allocation.busy)
268 1.25 riastrad cv_wait(&percpu_allocation.cv,
269 1.25 riastrad &percpu_allocation.lock);
270 1.25 riastrad percpu_allocation.busy = curlwp;
271 1.25 riastrad LIST_FOREACH(pc, &percpu_allocation.ctor_list, pc_list) {
272 1.25 riastrad KASSERT(pc->pc_ctor);
273 1.25 riastrad mutex_exit(&percpu_allocation.lock);
274 1.25 riastrad (*pc->pc_ctor)((char *)pcc->pcc_data + pc->pc_offset,
275 1.25 riastrad pc->pc_cookie, ci);
276 1.25 riastrad mutex_enter(&percpu_allocation.lock);
277 1.25 riastrad }
278 1.25 riastrad KASSERT(percpu_allocation.busy == curlwp);
279 1.25 riastrad percpu_allocation.busy = NULL;
280 1.25 riastrad cv_broadcast(&percpu_allocation.cv);
281 1.25 riastrad mutex_exit(&percpu_allocation.lock);
282 1.1 yamt }
283 1.1 yamt }
284 1.1 yamt
285 1.1 yamt /*
286 1.1 yamt * percpu_alloc: allocate percpu storage
287 1.1 yamt *
288 1.1 yamt * => called in thread context.
289 1.1 yamt * => considered as an expensive and rare operation.
290 1.2 yamt * => allocated storage is initialized with zeros.
291 1.1 yamt */
292 1.1 yamt
293 1.1 yamt percpu_t *
294 1.1 yamt percpu_alloc(size_t size)
295 1.1 yamt {
296 1.21 riastrad
297 1.21 riastrad return percpu_create(size, NULL, NULL, NULL);
298 1.21 riastrad }
299 1.21 riastrad
300 1.21 riastrad /*
301 1.21 riastrad * percpu_create: allocate percpu storage and associate ctor/dtor with it
302 1.21 riastrad *
303 1.21 riastrad * => called in thread context.
304 1.21 riastrad * => considered as an expensive and rare operation.
305 1.21 riastrad * => allocated storage is initialized by ctor, or zeros if ctor is null
306 1.21 riastrad * => percpu_free will call dtor first, if dtor is nonnull
307 1.21 riastrad * => ctor or dtor may sleep, even on allocation
308 1.21 riastrad */
309 1.21 riastrad
310 1.21 riastrad percpu_t *
311 1.21 riastrad percpu_create(size_t size, percpu_callback_t ctor, percpu_callback_t dtor,
312 1.21 riastrad void *cookie)
313 1.21 riastrad {
314 1.15 dyoung vmem_addr_t offset;
315 1.1 yamt percpu_t *pc;
316 1.1 yamt
317 1.3 yamt ASSERT_SLEEPABLE();
318 1.18 chs (void)vmem_alloc(percpu_offset_arena, size, VM_SLEEP | VM_BESTFIT,
319 1.18 chs &offset);
320 1.21 riastrad
321 1.21 riastrad pc = kmem_alloc(sizeof(*pc), KM_SLEEP);
322 1.21 riastrad pc->pc_offset = offset;
323 1.21 riastrad pc->pc_size = size;
324 1.25 riastrad pc->pc_ctor = ctor;
325 1.21 riastrad pc->pc_dtor = dtor;
326 1.21 riastrad pc->pc_cookie = cookie;
327 1.21 riastrad
328 1.21 riastrad if (ctor) {
329 1.21 riastrad CPU_INFO_ITERATOR cii;
330 1.21 riastrad struct cpu_info *ci;
331 1.21 riastrad void *buf;
332 1.21 riastrad
333 1.25 riastrad /*
334 1.25 riastrad * Wait until nobody is using the list of percpus with
335 1.25 riastrad * constructors.
336 1.25 riastrad */
337 1.25 riastrad mutex_enter(&percpu_allocation.lock);
338 1.25 riastrad while (percpu_allocation.busy)
339 1.25 riastrad cv_wait(&percpu_allocation.cv,
340 1.25 riastrad &percpu_allocation.lock);
341 1.25 riastrad percpu_allocation.busy = curlwp;
342 1.25 riastrad mutex_exit(&percpu_allocation.lock);
343 1.25 riastrad
344 1.25 riastrad /*
345 1.25 riastrad * Run the constructor for all CPUs. We use a
346 1.25 riastrad * temporary buffer wo that we need not hold the
347 1.25 riastrad * percpu_swap_lock while running the constructor.
348 1.25 riastrad */
349 1.21 riastrad buf = kmem_alloc(size, KM_SLEEP);
350 1.21 riastrad for (CPU_INFO_FOREACH(cii, ci)) {
351 1.21 riastrad memset(buf, 0, size);
352 1.21 riastrad (*ctor)(buf, cookie, ci);
353 1.21 riastrad percpu_traverse_enter();
354 1.21 riastrad memcpy(percpu_getptr_remote(pc, ci), buf, size);
355 1.21 riastrad percpu_traverse_exit();
356 1.21 riastrad }
357 1.21 riastrad explicit_memset(buf, 0, size);
358 1.21 riastrad kmem_free(buf, size);
359 1.25 riastrad
360 1.25 riastrad /*
361 1.25 riastrad * Insert the percpu into the list of percpus with
362 1.25 riastrad * constructors. We are now done using the list, so it
363 1.25 riastrad * is safe for concurrent percpu_create or concurrent
364 1.25 riastrad * percpu_init_cpu to run.
365 1.25 riastrad */
366 1.25 riastrad mutex_enter(&percpu_allocation.lock);
367 1.25 riastrad KASSERT(percpu_allocation.busy == curlwp);
368 1.25 riastrad percpu_allocation.busy = NULL;
369 1.25 riastrad cv_broadcast(&percpu_allocation.cv);
370 1.25 riastrad LIST_INSERT_HEAD(&percpu_allocation.ctor_list, pc, pc_list);
371 1.25 riastrad mutex_exit(&percpu_allocation.lock);
372 1.21 riastrad } else {
373 1.21 riastrad percpu_zero(pc, size);
374 1.21 riastrad }
375 1.21 riastrad
376 1.1 yamt return pc;
377 1.1 yamt }
378 1.1 yamt
379 1.1 yamt /*
380 1.5 yamt * percpu_free: free percpu storage
381 1.1 yamt *
382 1.1 yamt * => called in thread context.
383 1.1 yamt * => considered as an expensive and rare operation.
384 1.1 yamt */
385 1.1 yamt
386 1.1 yamt void
387 1.1 yamt percpu_free(percpu_t *pc, size_t size)
388 1.1 yamt {
389 1.1 yamt
390 1.3 yamt ASSERT_SLEEPABLE();
391 1.21 riastrad KASSERT(size == pc->pc_size);
392 1.21 riastrad
393 1.25 riastrad /*
394 1.25 riastrad * If there's a constructor, take the percpu off the list of
395 1.25 riastrad * percpus with constructors, but first wait until nobody is
396 1.25 riastrad * using the list.
397 1.25 riastrad */
398 1.25 riastrad if (pc->pc_ctor) {
399 1.25 riastrad mutex_enter(&percpu_allocation.lock);
400 1.25 riastrad while (percpu_allocation.busy)
401 1.25 riastrad cv_wait(&percpu_allocation.cv,
402 1.25 riastrad &percpu_allocation.lock);
403 1.25 riastrad LIST_REMOVE(pc, pc_list);
404 1.25 riastrad mutex_exit(&percpu_allocation.lock);
405 1.25 riastrad }
406 1.25 riastrad
407 1.25 riastrad /* If there's a destructor, run it now for all CPUs. */
408 1.21 riastrad if (pc->pc_dtor) {
409 1.21 riastrad CPU_INFO_ITERATOR cii;
410 1.21 riastrad struct cpu_info *ci;
411 1.21 riastrad void *buf;
412 1.21 riastrad
413 1.21 riastrad buf = kmem_alloc(size, KM_SLEEP);
414 1.21 riastrad for (CPU_INFO_FOREACH(cii, ci)) {
415 1.21 riastrad percpu_traverse_enter();
416 1.21 riastrad memcpy(buf, percpu_getptr_remote(pc, ci), size);
417 1.21 riastrad explicit_memset(percpu_getptr_remote(pc, ci), 0, size);
418 1.21 riastrad percpu_traverse_exit();
419 1.21 riastrad (*pc->pc_dtor)(buf, pc->pc_cookie, ci);
420 1.21 riastrad }
421 1.21 riastrad explicit_memset(buf, 0, size);
422 1.21 riastrad kmem_free(buf, size);
423 1.21 riastrad }
424 1.21 riastrad
425 1.1 yamt vmem_free(percpu_offset_arena, (vmem_addr_t)percpu_offset(pc), size);
426 1.21 riastrad kmem_free(pc, sizeof(*pc));
427 1.1 yamt }
428 1.1 yamt
429 1.1 yamt /*
430 1.4 thorpej * percpu_getref:
431 1.1 yamt *
432 1.1 yamt * => safe to be used in either thread or interrupt context
433 1.4 thorpej * => disables preemption; must be bracketed with a percpu_putref()
434 1.1 yamt */
435 1.1 yamt
436 1.1 yamt void *
437 1.4 thorpej percpu_getref(percpu_t *pc)
438 1.1 yamt {
439 1.1 yamt
440 1.17 uebayasi kpreempt_disable();
441 1.1 yamt return percpu_getptr_remote(pc, curcpu());
442 1.1 yamt }
443 1.1 yamt
444 1.1 yamt /*
445 1.4 thorpej * percpu_putref:
446 1.4 thorpej *
447 1.4 thorpej * => drops the preemption-disabled count after caller is done with per-cpu
448 1.4 thorpej * data
449 1.4 thorpej */
450 1.4 thorpej
451 1.4 thorpej void
452 1.4 thorpej percpu_putref(percpu_t *pc)
453 1.4 thorpej {
454 1.4 thorpej
455 1.17 uebayasi kpreempt_enable();
456 1.4 thorpej }
457 1.4 thorpej
458 1.4 thorpej /*
459 1.1 yamt * percpu_traverse_enter, percpu_traverse_exit, percpu_getptr_remote:
460 1.1 yamt * helpers to access remote cpu's percpu data.
461 1.1 yamt *
462 1.1 yamt * => called in thread context.
463 1.2 yamt * => percpu_traverse_enter can block low-priority xcalls.
464 1.1 yamt * => typical usage would be:
465 1.1 yamt *
466 1.1 yamt * sum = 0;
467 1.1 yamt * percpu_traverse_enter();
468 1.1 yamt * for (CPU_INFO_FOREACH(cii, ci)) {
469 1.1 yamt * unsigned int *p = percpu_getptr_remote(pc, ci);
470 1.1 yamt * sum += *p;
471 1.1 yamt * }
472 1.1 yamt * percpu_traverse_exit();
473 1.1 yamt */
474 1.1 yamt
475 1.1 yamt void
476 1.1 yamt percpu_traverse_enter(void)
477 1.1 yamt {
478 1.1 yamt
479 1.3 yamt ASSERT_SLEEPABLE();
480 1.1 yamt rw_enter(&percpu_swap_lock, RW_READER);
481 1.1 yamt }
482 1.1 yamt
483 1.1 yamt void
484 1.1 yamt percpu_traverse_exit(void)
485 1.1 yamt {
486 1.1 yamt
487 1.1 yamt rw_exit(&percpu_swap_lock);
488 1.1 yamt }
489 1.1 yamt
490 1.1 yamt void *
491 1.1 yamt percpu_getptr_remote(percpu_t *pc, struct cpu_info *ci)
492 1.1 yamt {
493 1.1 yamt
494 1.1 yamt return &((char *)cpu_percpu(ci)->pcc_data)[percpu_offset(pc)];
495 1.1 yamt }
496 1.1 yamt
497 1.1 yamt /*
498 1.1 yamt * percpu_foreach: call the specified callback function for each cpus.
499 1.1 yamt *
500 1.24 thorpej * => must be called from thread context.
501 1.24 thorpej * => callback executes on **current** CPU (or, really, arbitrary CPU,
502 1.24 thorpej * in case of preemption)
503 1.1 yamt * => caller should not rely on the cpu iteration order.
504 1.2 yamt * => the callback function should be minimum because it is executed with
505 1.2 yamt * holding a global lock, which can block low-priority xcalls.
506 1.2 yamt * eg. it's illegal for a callback function to sleep for memory allocation.
507 1.1 yamt */
508 1.1 yamt void
509 1.1 yamt percpu_foreach(percpu_t *pc, percpu_callback_t cb, void *arg)
510 1.1 yamt {
511 1.1 yamt CPU_INFO_ITERATOR cii;
512 1.1 yamt struct cpu_info *ci;
513 1.1 yamt
514 1.1 yamt percpu_traverse_enter();
515 1.1 yamt for (CPU_INFO_FOREACH(cii, ci)) {
516 1.2 yamt (*cb)(percpu_getptr_remote(pc, ci), arg, ci);
517 1.1 yamt }
518 1.1 yamt percpu_traverse_exit();
519 1.1 yamt }
520 1.24 thorpej
521 1.24 thorpej struct percpu_xcall_ctx {
522 1.24 thorpej percpu_callback_t ctx_cb;
523 1.24 thorpej void *ctx_arg;
524 1.24 thorpej };
525 1.24 thorpej
526 1.24 thorpej static void
527 1.24 thorpej percpu_xcfunc(void * const v1, void * const v2)
528 1.24 thorpej {
529 1.24 thorpej percpu_t * const pc = v1;
530 1.24 thorpej struct percpu_xcall_ctx * const ctx = v2;
531 1.24 thorpej
532 1.24 thorpej (*ctx->ctx_cb)(percpu_getref(pc), ctx->ctx_arg, curcpu());
533 1.24 thorpej percpu_putref(pc);
534 1.24 thorpej }
535 1.24 thorpej
536 1.24 thorpej /*
537 1.24 thorpej * percpu_foreach_xcall: call the specified callback function for each
538 1.24 thorpej * cpu. This version uses an xcall to run the callback on each cpu.
539 1.24 thorpej *
540 1.24 thorpej * => must be called from thread context.
541 1.24 thorpej * => callback executes on **remote** CPU in soft-interrupt context
542 1.24 thorpej * (at the specified soft interrupt priority).
543 1.24 thorpej * => caller should not rely on the cpu iteration order.
544 1.24 thorpej * => the callback function should be minimum because it may be
545 1.24 thorpej * executed in soft-interrupt context. eg. it's illegal for
546 1.24 thorpej * a callback function to sleep for memory allocation.
547 1.24 thorpej */
548 1.24 thorpej void
549 1.24 thorpej percpu_foreach_xcall(percpu_t *pc, u_int xcflags, percpu_callback_t cb,
550 1.24 thorpej void *arg)
551 1.24 thorpej {
552 1.24 thorpej struct percpu_xcall_ctx ctx = {
553 1.24 thorpej .ctx_cb = cb,
554 1.24 thorpej .ctx_arg = arg,
555 1.24 thorpej };
556 1.24 thorpej CPU_INFO_ITERATOR cii;
557 1.24 thorpej struct cpu_info *ci;
558 1.24 thorpej
559 1.24 thorpej for (CPU_INFO_FOREACH(cii, ci)) {
560 1.24 thorpej xc_wait(xc_unicast(xcflags, percpu_xcfunc, pc, &ctx, ci));
561 1.24 thorpej }
562 1.24 thorpej }
563