xref: /openbmc/linux/include/linux/percpu.h (revision 3c615294)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
21da177e4SLinus Torvalds #ifndef __LINUX_PERCPU_H
31da177e4SLinus Torvalds #define __LINUX_PERCPU_H
47ff6f082SMartin Peschke 
5309381feSSasha Levin #include <linux/mmdebug.h>
60a3021f4SRobert P. J. Day #include <linux/preempt.h>
71da177e4SLinus Torvalds #include <linux/smp.h>
87ff6f082SMartin Peschke #include <linux/cpumask.h>
96a242909STejun Heo #include <linux/pfn.h>
10de380b55STejun Heo #include <linux/init.h>
1154da6a09SPeter Zijlstra #include <linux/cleanup.h>
127ff6f082SMartin Peschke 
131da177e4SLinus Torvalds #include <asm/percpu.h>
141da177e4SLinus Torvalds 
156a242909STejun Heo /* enough to cover all DEFINE_PER_CPUs in modules */
16b00742d3SJeremy Fitzhardinge #ifdef CONFIG_MODULES
176a242909STejun Heo #define PERCPU_MODULE_RESERVE		(8 << 10)
18b00742d3SJeremy Fitzhardinge #else
19b00742d3SJeremy Fitzhardinge #define PERCPU_MODULE_RESERVE		0
201da177e4SLinus Torvalds #endif
211da177e4SLinus Torvalds 
228d408b4bSTejun Heo /* minimum unit size, also is the maximum supported allocation size */
236abad5acSTejun Heo #define PCPU_MIN_UNIT_SIZE		PFN_ALIGN(32 << 10)
248d408b4bSTejun Heo 
25d2f3c384SDennis Zhou (Facebook) /* minimum allocation size and shift in bytes */
26d2f3c384SDennis Zhou (Facebook) #define PCPU_MIN_ALLOC_SHIFT		2
27d2f3c384SDennis Zhou (Facebook) #define PCPU_MIN_ALLOC_SIZE		(1 << PCPU_MIN_ALLOC_SHIFT)
28d2f3c384SDennis Zhou (Facebook) 
298d408b4bSTejun Heo /*
30b239f7daSDennis Zhou  * The PCPU_BITMAP_BLOCK_SIZE must be the same size as PAGE_SIZE as the
31b239f7daSDennis Zhou  * updating of hints is used to manage the nr_empty_pop_pages in both
32b239f7daSDennis Zhou  * the chunk and globally.
33ca460b3cSDennis Zhou (Facebook)  */
34ca460b3cSDennis Zhou (Facebook) #define PCPU_BITMAP_BLOCK_SIZE		PAGE_SIZE
35ca460b3cSDennis Zhou (Facebook) #define PCPU_BITMAP_BLOCK_BITS		(PCPU_BITMAP_BLOCK_SIZE >>	\
36ca460b3cSDennis Zhou (Facebook) 					 PCPU_MIN_ALLOC_SHIFT)
37ca460b3cSDennis Zhou (Facebook) 
38*3c615294SGONG, Ruiqi #ifdef CONFIG_RANDOM_KMALLOC_CACHES
39*3c615294SGONG, Ruiqi #define PERCPU_DYNAMIC_SIZE_SHIFT      12
40*3c615294SGONG, Ruiqi #else
41*3c615294SGONG, Ruiqi #define PERCPU_DYNAMIC_SIZE_SHIFT      10
42*3c615294SGONG, Ruiqi #endif
43*3c615294SGONG, Ruiqi 
44ca460b3cSDennis Zhou (Facebook) /*
45099a19d9STejun Heo  * Percpu allocator can serve percpu allocations before slab is
46099a19d9STejun Heo  * initialized which allows slab to depend on the percpu allocator.
47d667c949SBaoquan He  * The following parameter decide how much resource to preallocate
48d667c949SBaoquan He  * for this.  Keep PERCPU_DYNAMIC_RESERVE equal to or larger than
49d667c949SBaoquan He  * PERCPU_DYNAMIC_EARLY_SIZE.
50099a19d9STejun Heo  */
51*3c615294SGONG, Ruiqi #define PERCPU_DYNAMIC_EARLY_SIZE	(20 << PERCPU_DYNAMIC_SIZE_SHIFT)
52099a19d9STejun Heo 
53099a19d9STejun Heo /*
548d408b4bSTejun Heo  * PERCPU_DYNAMIC_RESERVE indicates the amount of free area to piggy
556b19b0c2STejun Heo  * back on the first chunk for dynamic percpu allocation if arch is
566b19b0c2STejun Heo  * manually allocating and mapping it for faster access (as a part of
576b19b0c2STejun Heo  * large page mapping for example).
588d408b4bSTejun Heo  *
596b19b0c2STejun Heo  * The following values give between one and two pages of free space
606b19b0c2STejun Heo  * after typical minimal boot (2-way SMP, single disk and NIC) with
616b19b0c2STejun Heo  * both defconfig and a distro config on x86_64 and 32.  More
626b19b0c2STejun Heo  * intelligent way to determine this would be nice.
638d408b4bSTejun Heo  */
648d408b4bSTejun Heo #if BITS_PER_LONG > 32
65*3c615294SGONG, Ruiqi #define PERCPU_DYNAMIC_RESERVE		(28 << PERCPU_DYNAMIC_SIZE_SHIFT)
668d408b4bSTejun Heo #else
67*3c615294SGONG, Ruiqi #define PERCPU_DYNAMIC_RESERVE		(20 << PERCPU_DYNAMIC_SIZE_SHIFT)
688d408b4bSTejun Heo #endif
698d408b4bSTejun Heo 
70fbf59bc9STejun Heo extern void *pcpu_base_addr;
71fb435d52STejun Heo extern const unsigned long *pcpu_unit_offsets;
72fbf59bc9STejun Heo 
73fd1e8a1fSTejun Heo struct pcpu_group_info {
74fd1e8a1fSTejun Heo 	int			nr_units;	/* aligned # of units */
75fd1e8a1fSTejun Heo 	unsigned long		base_offset;	/* base address offset */
76fd1e8a1fSTejun Heo 	unsigned int		*cpu_map;	/* unit->cpu map, empty
77fd1e8a1fSTejun Heo 						 * entries contain NR_CPUS */
78fd1e8a1fSTejun Heo };
79fd1e8a1fSTejun Heo 
80fd1e8a1fSTejun Heo struct pcpu_alloc_info {
81fd1e8a1fSTejun Heo 	size_t			static_size;
82fd1e8a1fSTejun Heo 	size_t			reserved_size;
83fd1e8a1fSTejun Heo 	size_t			dyn_size;
84fd1e8a1fSTejun Heo 	size_t			unit_size;
85fd1e8a1fSTejun Heo 	size_t			atom_size;
86fd1e8a1fSTejun Heo 	size_t			alloc_size;
87fd1e8a1fSTejun Heo 	size_t			__ai_size;	/* internal, don't use */
88fd1e8a1fSTejun Heo 	int			nr_groups;	/* 0 if grouping unnecessary */
89fd1e8a1fSTejun Heo 	struct pcpu_group_info	groups[];
90fd1e8a1fSTejun Heo };
91fd1e8a1fSTejun Heo 
92f58dc01bSTejun Heo enum pcpu_fc {
93f58dc01bSTejun Heo 	PCPU_FC_AUTO,
94f58dc01bSTejun Heo 	PCPU_FC_EMBED,
95f58dc01bSTejun Heo 	PCPU_FC_PAGE,
96f58dc01bSTejun Heo 
97f58dc01bSTejun Heo 	PCPU_FC_NR,
98f58dc01bSTejun Heo };
9917f3609cSAndi Kleen extern const char * const pcpu_fc_names[PCPU_FC_NR];
100f58dc01bSTejun Heo 
101f58dc01bSTejun Heo extern enum pcpu_fc pcpu_chosen_fc;
102f58dc01bSTejun Heo 
1031ca3fb3aSKefeng Wang typedef int (pcpu_fc_cpu_to_node_fn_t)(int cpu);
104a530b795STejun Heo typedef int (pcpu_fc_cpu_distance_fn_t)(unsigned int from, unsigned int to);
105fbf59bc9STejun Heo 
106fd1e8a1fSTejun Heo extern struct pcpu_alloc_info * __init pcpu_alloc_alloc_info(int nr_groups,
107fd1e8a1fSTejun Heo 							     int nr_units);
108fd1e8a1fSTejun Heo extern void __init pcpu_free_alloc_info(struct pcpu_alloc_info *ai);
109033e48fbSTejun Heo 
110163fa234SKefeng Wang extern void __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
111fd1e8a1fSTejun Heo 					 void *base_addr);
1128d408b4bSTejun Heo 
1134ba6ce25STejun Heo extern int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size,
114c8826dd5STejun Heo 				size_t atom_size,
115c8826dd5STejun Heo 				pcpu_fc_cpu_distance_fn_t cpu_distance_fn,
11623f91716SKefeng Wang 				pcpu_fc_cpu_to_node_fn_t cpu_to_nd_fn);
11766c3a757STejun Heo 
11808fc4580STejun Heo #ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK
11920c03576SKefeng Wang void __init pcpu_populate_pte(unsigned long addr);
120fb435d52STejun Heo extern int __init pcpu_page_first_chunk(size_t reserved_size,
12120c03576SKefeng Wang 				pcpu_fc_cpu_to_node_fn_t cpu_to_nd_fn);
12208fc4580STejun Heo #endif
123d4b95f80STejun Heo 
12417197dd4SKees Cook extern void __percpu *__alloc_reserved_percpu(size_t size, size_t align) __alloc_size(1);
125383776faSThomas Gleixner extern bool __is_kernel_percpu_address(unsigned long addr, unsigned long *can_addr);
12610fad5e4STejun Heo extern bool is_kernel_percpu_address(unsigned long addr);
127f2a8205cSTejun Heo 
128bbddff05STejun Heo #if !defined(CONFIG_SMP) || !defined(CONFIG_HAVE_SETUP_PER_CPU_AREA)
129e74e3962STejun Heo extern void __init setup_per_cpu_areas(void);
130e74e3962STejun Heo #endif
131e74e3962STejun Heo 
13217197dd4SKees Cook extern void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp) __alloc_size(1);
13317197dd4SKees Cook extern void __percpu *__alloc_percpu(size_t size, size_t align) __alloc_size(1);
134de380b55STejun Heo extern void free_percpu(void __percpu *__pdata);
13554da6a09SPeter Zijlstra 
13654da6a09SPeter Zijlstra DEFINE_FREE(free_percpu, void __percpu *, free_percpu(_T))
13754da6a09SPeter Zijlstra 
138de380b55STejun Heo extern phys_addr_t per_cpu_ptr_to_phys(void *addr);
139de380b55STejun Heo 
1405835d96eSTejun Heo #define alloc_percpu_gfp(type, gfp)					\
1415835d96eSTejun Heo 	(typeof(type) __percpu *)__alloc_percpu_gfp(sizeof(type),	\
1425835d96eSTejun Heo 						__alignof__(type), gfp)
14364ef291fSTejun Heo #define alloc_percpu(type)						\
1445835d96eSTejun Heo 	(typeof(type) __percpu *)__alloc_percpu(sizeof(type),		\
1455835d96eSTejun Heo 						__alignof__(type))
146f2a8205cSTejun Heo 
1477e8a6304SDennis Zhou (Facebook) extern unsigned long pcpu_nr_pages(void);
1487e8a6304SDennis Zhou (Facebook) 
1491da177e4SLinus Torvalds #endif /* __LINUX_PERCPU_H */
150