xref: /f-stack/freebsd/sys/pcpu.h (revision 22ce4aff)
1a9643ea8Slogwang /*-
2*22ce4affSfengbojiang  * SPDX-License-Identifier: BSD-3-Clause
3*22ce4affSfengbojiang  *
4a9643ea8Slogwang  * Copyright (c) 2001 Wind River Systems, Inc.
5a9643ea8Slogwang  * All rights reserved.
6a9643ea8Slogwang  * Written by: John Baldwin <[email protected]>
7a9643ea8Slogwang  *
8a9643ea8Slogwang  * Redistribution and use in source and binary forms, with or without
9a9643ea8Slogwang  * modification, are permitted provided that the following conditions
10a9643ea8Slogwang  * are met:
11a9643ea8Slogwang  * 1. Redistributions of source code must retain the above copyright
12a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer.
13a9643ea8Slogwang  * 2. Redistributions in binary form must reproduce the above copyright
14a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer in the
15a9643ea8Slogwang  *    documentation and/or other materials provided with the distribution.
16*22ce4affSfengbojiang  * 3. Neither the name of the author nor the names of any co-contributors
17a9643ea8Slogwang  *    may be used to endorse or promote products derived from this software
18a9643ea8Slogwang  *    without specific prior written permission.
19a9643ea8Slogwang  *
20a9643ea8Slogwang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21a9643ea8Slogwang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22a9643ea8Slogwang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23a9643ea8Slogwang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24a9643ea8Slogwang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25a9643ea8Slogwang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26a9643ea8Slogwang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27a9643ea8Slogwang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28a9643ea8Slogwang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29a9643ea8Slogwang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30a9643ea8Slogwang  * SUCH DAMAGE.
31a9643ea8Slogwang  *
32a9643ea8Slogwang  * $FreeBSD$
33a9643ea8Slogwang  */
34a9643ea8Slogwang 
35a9643ea8Slogwang #ifndef _SYS_PCPU_H_
36a9643ea8Slogwang #define	_SYS_PCPU_H_
37a9643ea8Slogwang 
38a9643ea8Slogwang #ifdef LOCORE
39a9643ea8Slogwang #error "no assembler-serviceable parts inside"
40a9643ea8Slogwang #endif
41a9643ea8Slogwang 
42*22ce4affSfengbojiang #include <sys/param.h>
43a9643ea8Slogwang #include <sys/_cpuset.h>
44a9643ea8Slogwang #include <sys/_lock.h>
45a9643ea8Slogwang #include <sys/_mutex.h>
46a9643ea8Slogwang #include <sys/_sx.h>
47a9643ea8Slogwang #include <sys/queue.h>
48a9643ea8Slogwang #include <sys/_rmlock.h>
49a9643ea8Slogwang #include <sys/resource.h>
50a9643ea8Slogwang #include <machine/pcpu.h>
51a9643ea8Slogwang 
52a9643ea8Slogwang #define	DPCPU_SETNAME		"set_pcpu"
53a9643ea8Slogwang #define	DPCPU_SYMPREFIX		"pcpu_entry_"
54a9643ea8Slogwang 
55a9643ea8Slogwang #ifdef _KERNEL
56a9643ea8Slogwang 
57a9643ea8Slogwang /*
58a9643ea8Slogwang  * Define a set for pcpu data.
59a9643ea8Slogwang  */
60a9643ea8Slogwang extern uintptr_t *__start_set_pcpu;
61a9643ea8Slogwang __GLOBL(__start_set_pcpu);
62a9643ea8Slogwang extern uintptr_t *__stop_set_pcpu;
63a9643ea8Slogwang __GLOBL(__stop_set_pcpu);
64a9643ea8Slogwang 
65a9643ea8Slogwang /*
66a9643ea8Slogwang  * Array of dynamic pcpu base offsets.  Indexed by id.
67a9643ea8Slogwang  */
68a9643ea8Slogwang extern uintptr_t dpcpu_off[];
69a9643ea8Slogwang 
70a9643ea8Slogwang /*
71a9643ea8Slogwang  * Convenience defines.
72a9643ea8Slogwang  */
73a9643ea8Slogwang #define	DPCPU_START		((uintptr_t)&__start_set_pcpu)
74a9643ea8Slogwang #define	DPCPU_STOP		((uintptr_t)&__stop_set_pcpu)
75a9643ea8Slogwang #define	DPCPU_BYTES		(DPCPU_STOP - DPCPU_START)
76a9643ea8Slogwang #define	DPCPU_MODMIN		2048
77a9643ea8Slogwang #define	DPCPU_SIZE		roundup2(DPCPU_BYTES, PAGE_SIZE)
78a9643ea8Slogwang #define	DPCPU_MODSIZE		(DPCPU_SIZE - (DPCPU_BYTES - DPCPU_MODMIN))
79a9643ea8Slogwang 
80a9643ea8Slogwang /*
81a9643ea8Slogwang  * Declaration and definition.
82a9643ea8Slogwang  */
83a9643ea8Slogwang #define	DPCPU_NAME(n)		pcpu_entry_##n
84a9643ea8Slogwang #define	DPCPU_DECLARE(t, n)	extern t DPCPU_NAME(n)
85*22ce4affSfengbojiang /* struct _hack is to stop this from being used with the static keyword. */
86*22ce4affSfengbojiang #define	DPCPU_DEFINE(t, n)	\
87*22ce4affSfengbojiang     struct _hack; t DPCPU_NAME(n) __section(DPCPU_SETNAME) __used
88*22ce4affSfengbojiang #if defined(KLD_MODULE) && (defined(__aarch64__) || defined(__riscv) \
89*22ce4affSfengbojiang 		|| defined(__powerpc64__))
90*22ce4affSfengbojiang /*
91*22ce4affSfengbojiang  * On some architectures the compiler will use PC-relative load to
92*22ce4affSfengbojiang  * find the address of DPCPU data with the static keyword. We then
93*22ce4affSfengbojiang  * use this to find the offset of the data in a per-CPU region.
94*22ce4affSfengbojiang  * This works for in the kernel as we can allocate the space ahead
95*22ce4affSfengbojiang  * of time, however modules need to allocate a sepatate space and
96*22ce4affSfengbojiang  * then use relocations to fix the address of the data. As
97*22ce4affSfengbojiang  * PC-relative data doesn't have a relocation there is nothing for
98*22ce4affSfengbojiang  * the kernel module linker to fix so data is accessed from the
99*22ce4affSfengbojiang  * wrong location.
100*22ce4affSfengbojiang  *
101*22ce4affSfengbojiang  * This is a workaround until a better solution can be found.
102*22ce4affSfengbojiang  *
103*22ce4affSfengbojiang  * VNET_DEFINE_STATIC also has the same workaround.
104*22ce4affSfengbojiang  */
105*22ce4affSfengbojiang #define	DPCPU_DEFINE_STATIC(t, n)	\
106*22ce4affSfengbojiang     t DPCPU_NAME(n) __section(DPCPU_SETNAME) __used
107*22ce4affSfengbojiang #else
108*22ce4affSfengbojiang #define	DPCPU_DEFINE_STATIC(t, n)	\
109*22ce4affSfengbojiang     static t DPCPU_NAME(n) __section(DPCPU_SETNAME) __used
110*22ce4affSfengbojiang #endif
111a9643ea8Slogwang 
112a9643ea8Slogwang /*
113a9643ea8Slogwang  * Accessors with a given base.
114a9643ea8Slogwang  */
115a9643ea8Slogwang #define	_DPCPU_PTR(b, n)						\
116a9643ea8Slogwang     (__typeof(DPCPU_NAME(n))*)((b) + (uintptr_t)&DPCPU_NAME(n))
117a9643ea8Slogwang #define	_DPCPU_GET(b, n)	(*_DPCPU_PTR(b, n))
118a9643ea8Slogwang #define	_DPCPU_SET(b, n, v)	(*_DPCPU_PTR(b, n) = v)
119a9643ea8Slogwang 
120a9643ea8Slogwang /*
121a9643ea8Slogwang  * Accessors for the current cpu.
122a9643ea8Slogwang  */
123a9643ea8Slogwang #define	DPCPU_PTR(n)		_DPCPU_PTR(PCPU_GET(dynamic), n)
124a9643ea8Slogwang #define	DPCPU_GET(n)		(*DPCPU_PTR(n))
125a9643ea8Slogwang #define	DPCPU_SET(n, v)		(*DPCPU_PTR(n) = v)
126a9643ea8Slogwang 
127a9643ea8Slogwang /*
128a9643ea8Slogwang  * Accessors for remote cpus.
129a9643ea8Slogwang  */
130a9643ea8Slogwang #define	DPCPU_ID_PTR(i, n)	_DPCPU_PTR(dpcpu_off[(i)], n)
131a9643ea8Slogwang #define	DPCPU_ID_GET(i, n)	(*DPCPU_ID_PTR(i, n))
132a9643ea8Slogwang #define	DPCPU_ID_SET(i, n, v)	(*DPCPU_ID_PTR(i, n) = v)
133a9643ea8Slogwang 
134a9643ea8Slogwang /*
135a9643ea8Slogwang  * Utility macros.
136a9643ea8Slogwang  */
137a9643ea8Slogwang #define	DPCPU_SUM(n) __extension__					\
138a9643ea8Slogwang ({									\
139a9643ea8Slogwang 	u_int _i;							\
140a9643ea8Slogwang 	__typeof(*DPCPU_PTR(n)) sum;					\
141a9643ea8Slogwang 									\
142a9643ea8Slogwang 	sum = 0;							\
143a9643ea8Slogwang 	CPU_FOREACH(_i) {						\
144a9643ea8Slogwang 		sum += *DPCPU_ID_PTR(_i, n);				\
145a9643ea8Slogwang 	}								\
146a9643ea8Slogwang 	sum;								\
147a9643ea8Slogwang })
148a9643ea8Slogwang 
149a9643ea8Slogwang #define	DPCPU_VARSUM(n, var) __extension__				\
150a9643ea8Slogwang ({									\
151a9643ea8Slogwang 	u_int _i;							\
152a9643ea8Slogwang 	__typeof((DPCPU_PTR(n))->var) sum;				\
153a9643ea8Slogwang 									\
154a9643ea8Slogwang 	sum = 0;							\
155a9643ea8Slogwang 	CPU_FOREACH(_i) {						\
156a9643ea8Slogwang 		sum += (DPCPU_ID_PTR(_i, n))->var;			\
157a9643ea8Slogwang 	}								\
158a9643ea8Slogwang 	sum;								\
159a9643ea8Slogwang })
160a9643ea8Slogwang 
161a9643ea8Slogwang #define	DPCPU_ZERO(n) do {						\
162a9643ea8Slogwang 	u_int _i;							\
163a9643ea8Slogwang 									\
164a9643ea8Slogwang 	CPU_FOREACH(_i) {						\
165a9643ea8Slogwang 		bzero(DPCPU_ID_PTR(_i, n), sizeof(*DPCPU_PTR(n)));	\
166a9643ea8Slogwang 	}								\
167a9643ea8Slogwang } while(0)
168a9643ea8Slogwang 
169a9643ea8Slogwang #endif /* _KERNEL */
170a9643ea8Slogwang 
171a9643ea8Slogwang /*
172a9643ea8Slogwang  * This structure maps out the global data that needs to be kept on a
173a9643ea8Slogwang  * per-cpu basis.  The members are accessed via the PCPU_GET/SET/PTR
174a9643ea8Slogwang  * macros defined in <machine/pcpu.h>.  Machine dependent fields are
175a9643ea8Slogwang  * defined in the PCPU_MD_FIELDS macro defined in <machine/pcpu.h>.
176a9643ea8Slogwang  */
177a9643ea8Slogwang struct pcpu {
178a9643ea8Slogwang 	struct thread	*pc_curthread;		/* Current thread */
179a9643ea8Slogwang 	struct thread	*pc_idlethread;		/* Idle thread */
180a9643ea8Slogwang 	struct thread	*pc_fpcurthread;	/* Fp state owner */
181a9643ea8Slogwang 	struct thread	*pc_deadthread;		/* Zombie thread or NULL */
182a9643ea8Slogwang 	struct pcb	*pc_curpcb;		/* Current pcb */
183*22ce4affSfengbojiang 	void		*pc_sched;		/* Scheduler state */
184a9643ea8Slogwang 	uint64_t	pc_switchtime;		/* cpu_ticks() at last csw */
185a9643ea8Slogwang 	int		pc_switchticks;		/* `ticks' at last csw */
186a9643ea8Slogwang 	u_int		pc_cpuid;		/* This cpu number */
187a9643ea8Slogwang 	STAILQ_ENTRY(pcpu) pc_allcpu;
188a9643ea8Slogwang 	struct lock_list_entry *pc_spinlocks;
189a9643ea8Slogwang 	long		pc_cp_time[CPUSTATES];	/* statclock ticks */
190a9643ea8Slogwang 	struct device	*pc_device;
191a9643ea8Slogwang 	void		*pc_netisr;		/* netisr SWI cookie */
192a9643ea8Slogwang 	int		pc_unused1;		/* unused field */
193a9643ea8Slogwang 	int		pc_domain;		/* Memory domain. */
194a9643ea8Slogwang 	struct rm_queue	pc_rm_queue;		/* rmlock list of trackers */
195a9643ea8Slogwang 	uintptr_t	pc_dynamic;		/* Dynamic per-cpu data area */
196*22ce4affSfengbojiang 	uint64_t	pc_early_dummy_counter;	/* Startup time counter(9) */
197*22ce4affSfengbojiang 	uintptr_t	pc_zpcpu_offset;	/* Offset into zpcpu allocs */
198a9643ea8Slogwang 
199a9643ea8Slogwang 	/*
200a9643ea8Slogwang 	 * Keep MD fields last, so that CPU-specific variations on a
201a9643ea8Slogwang 	 * single architecture don't result in offset variations of
202a9643ea8Slogwang 	 * the machine-independent fields of the pcpu.  Even though
203a9643ea8Slogwang 	 * the pcpu structure is private to the kernel, some ports
204a9643ea8Slogwang 	 * (e.g., lsof, part of gtop) define _KERNEL and include this
205a9643ea8Slogwang 	 * header.  While strictly speaking this is wrong, there's no
206a9643ea8Slogwang 	 * reason not to keep the offsets of the MI fields constant
207a9643ea8Slogwang 	 * if only to make kernel debugging easier.
208a9643ea8Slogwang 	 */
209a9643ea8Slogwang 	PCPU_MD_FIELDS;
210a9643ea8Slogwang } __aligned(CACHE_LINE_SIZE);
211a9643ea8Slogwang 
212a9643ea8Slogwang #ifdef _KERNEL
213a9643ea8Slogwang 
214a9643ea8Slogwang STAILQ_HEAD(cpuhead, pcpu);
215a9643ea8Slogwang 
216a9643ea8Slogwang extern struct cpuhead cpuhead;
217a9643ea8Slogwang extern struct pcpu *cpuid_to_pcpu[];
218a9643ea8Slogwang 
219a9643ea8Slogwang #define	curcpu		PCPU_GET(cpuid)
220*22ce4affSfengbojiang #define	curvidata	PCPU_GET(vidata)
221*22ce4affSfengbojiang 
222*22ce4affSfengbojiang #define UMA_PCPU_ALLOC_SIZE		PAGE_SIZE
223*22ce4affSfengbojiang 
224*22ce4affSfengbojiang #include <machine/pcpu_aux.h>
225*22ce4affSfengbojiang 
226a9643ea8Slogwang #ifndef curthread
227a9643ea8Slogwang #define	curthread	PCPU_GET(curthread)
228a9643ea8Slogwang #endif
229*22ce4affSfengbojiang #define	curproc		(curthread->td_proc)
230*22ce4affSfengbojiang 
231*22ce4affSfengbojiang #ifndef ZPCPU_ASSERT_PROTECTED
232*22ce4affSfengbojiang #define ZPCPU_ASSERT_PROTECTED() MPASS(curthread->td_critnest > 0)
233*22ce4affSfengbojiang #endif
234*22ce4affSfengbojiang 
235*22ce4affSfengbojiang #ifndef zpcpu_offset_cpu
236*22ce4affSfengbojiang #define zpcpu_offset_cpu(cpu)	(UMA_PCPU_ALLOC_SIZE * cpu)
237*22ce4affSfengbojiang #endif
238*22ce4affSfengbojiang #ifndef zpcpu_offset
239*22ce4affSfengbojiang #define zpcpu_offset()		(PCPU_GET(zpcpu_offset))
240*22ce4affSfengbojiang #endif
241*22ce4affSfengbojiang 
242*22ce4affSfengbojiang #ifndef zpcpu_base_to_offset
243*22ce4affSfengbojiang #define zpcpu_base_to_offset(base) (base)
244*22ce4affSfengbojiang #endif
245*22ce4affSfengbojiang #ifndef zpcpu_offset_to_base
246*22ce4affSfengbojiang #define zpcpu_offset_to_base(base) (base)
247*22ce4affSfengbojiang #endif
248a9643ea8Slogwang 
249a9643ea8Slogwang /* Accessor to elements allocated via UMA_ZONE_PCPU zone. */
250*22ce4affSfengbojiang #define zpcpu_get(base) ({								\
251*22ce4affSfengbojiang 	__typeof(base) _ptr = (void *)((char *)(base) + zpcpu_offset());		\
252*22ce4affSfengbojiang 	_ptr;										\
253*22ce4affSfengbojiang })
254a9643ea8Slogwang 
255*22ce4affSfengbojiang #define zpcpu_get_cpu(base, cpu) ({							\
256*22ce4affSfengbojiang 	__typeof(base) _ptr = (void *)((char *)(base) +	zpcpu_offset_cpu(cpu));		\
257*22ce4affSfengbojiang 	_ptr;										\
258*22ce4affSfengbojiang })
259a9643ea8Slogwang 
260*22ce4affSfengbojiang /*
261*22ce4affSfengbojiang  * This operation is NOT atomic and does not post any barriers.
262*22ce4affSfengbojiang  * If you use this the assumption is that the target CPU will not
263*22ce4affSfengbojiang  * be modifying this variable.
264*22ce4affSfengbojiang  * If you need atomicity use xchg.
265*22ce4affSfengbojiang  * */
266*22ce4affSfengbojiang #define zpcpu_replace(base, val) ({					\
267*22ce4affSfengbojiang 	__typeof(val) *_ptr = zpcpu_get(base);				\
268*22ce4affSfengbojiang 	__typeof(val) _old;						\
269*22ce4affSfengbojiang 									\
270*22ce4affSfengbojiang 	_old = *_ptr;							\
271*22ce4affSfengbojiang 	*_ptr = val;							\
272*22ce4affSfengbojiang 	_old;								\
273*22ce4affSfengbojiang })
274a9643ea8Slogwang 
275*22ce4affSfengbojiang #define zpcpu_replace_cpu(base, val, cpu) ({				\
276*22ce4affSfengbojiang 	__typeof(val) *_ptr = zpcpu_get_cpu(base, cpu);			\
277*22ce4affSfengbojiang 	__typeof(val) _old;						\
278*22ce4affSfengbojiang 									\
279*22ce4affSfengbojiang 	_old = *_ptr;							\
280*22ce4affSfengbojiang 	*_ptr = val;							\
281*22ce4affSfengbojiang 	_old;								\
282*22ce4affSfengbojiang })
283*22ce4affSfengbojiang 
284*22ce4affSfengbojiang #ifndef zpcpu_set_protected
285*22ce4affSfengbojiang #define zpcpu_set_protected(base, val) ({				\
286*22ce4affSfengbojiang 	ZPCPU_ASSERT_PROTECTED();					\
287*22ce4affSfengbojiang 	__typeof(val) *_ptr = zpcpu_get(base);				\
288*22ce4affSfengbojiang 									\
289*22ce4affSfengbojiang 	*_ptr = (val);							\
290*22ce4affSfengbojiang })
291*22ce4affSfengbojiang #endif
292*22ce4affSfengbojiang 
293*22ce4affSfengbojiang #ifndef zpcpu_add_protected
294*22ce4affSfengbojiang #define zpcpu_add_protected(base, val) ({				\
295*22ce4affSfengbojiang 	ZPCPU_ASSERT_PROTECTED();					\
296*22ce4affSfengbojiang 	__typeof(val) *_ptr = zpcpu_get(base);				\
297*22ce4affSfengbojiang 									\
298*22ce4affSfengbojiang 	*_ptr += (val);							\
299*22ce4affSfengbojiang })
300*22ce4affSfengbojiang #endif
301*22ce4affSfengbojiang 
302*22ce4affSfengbojiang #ifndef zpcpu_sub_protected
303*22ce4affSfengbojiang #define zpcpu_sub_protected(base, val) ({				\
304*22ce4affSfengbojiang 	ZPCPU_ASSERT_PROTECTED();					\
305*22ce4affSfengbojiang 	__typeof(val) *_ptr = zpcpu_get(base);				\
306*22ce4affSfengbojiang 									\
307*22ce4affSfengbojiang 	*_ptr -= (val);							\
308*22ce4affSfengbojiang })
309*22ce4affSfengbojiang #endif
310a9643ea8Slogwang 
311a9643ea8Slogwang /*
312a9643ea8Slogwang  * Machine dependent callouts.  cpu_pcpu_init() is responsible for
313a9643ea8Slogwang  * initializing machine dependent fields of struct pcpu, and
314a9643ea8Slogwang  * db_show_mdpcpu() is responsible for handling machine dependent
315a9643ea8Slogwang  * fields for the DDB 'show pcpu' command.
316a9643ea8Slogwang  */
317a9643ea8Slogwang void	cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size);
318a9643ea8Slogwang void	db_show_mdpcpu(struct pcpu *pcpu);
319a9643ea8Slogwang 
320a9643ea8Slogwang void	*dpcpu_alloc(int size);
321a9643ea8Slogwang void	dpcpu_copy(void *s, int size);
322a9643ea8Slogwang void	dpcpu_free(void *s, int size);
323a9643ea8Slogwang void	dpcpu_init(void *dpcpu, int cpuid);
324a9643ea8Slogwang void	pcpu_destroy(struct pcpu *pcpu);
325a9643ea8Slogwang struct	pcpu *pcpu_find(u_int cpuid);
326a9643ea8Slogwang void	pcpu_init(struct pcpu *pcpu, int cpuid, size_t size);
327a9643ea8Slogwang 
328a9643ea8Slogwang #endif /* _KERNEL */
329a9643ea8Slogwang 
330a9643ea8Slogwang #endif /* !_SYS_PCPU_H_ */
331