Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0 */
2 : #ifndef __LINUX_MEMORY_HOTPLUG_H
3 : #define __LINUX_MEMORY_HOTPLUG_H
4 :
5 : #include <linux/mmzone.h>
6 : #include <linux/spinlock.h>
7 : #include <linux/notifier.h>
8 : #include <linux/bug.h>
9 :
10 : struct page;
11 : struct zone;
12 : struct pglist_data;
13 : struct mem_section;
14 : struct memory_block;
15 : struct resource;
16 : struct vmem_altmap;
17 :
18 : #ifdef CONFIG_MEMORY_HOTPLUG
19 : struct page *pfn_to_online_page(unsigned long pfn);
20 :
21 : /*
22 : * Types for free bootmem stored in page->lru.next. These have to be in
23 : * some random range in unsigned long space for debugging purposes.
24 : */
25 : enum {
26 : MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE = 12,
27 : SECTION_INFO = MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE,
28 : MIX_SECTION_INFO,
29 : NODE_INFO,
30 : MEMORY_HOTPLUG_MAX_BOOTMEM_TYPE = NODE_INFO,
31 : };
32 :
33 : /* Types for control the zone type of onlined and offlined memory */
34 : enum {
35 : /* Offline the memory. */
36 : MMOP_OFFLINE = 0,
37 : /* Online the memory. Zone depends, see default_zone_for_pfn(). */
38 : MMOP_ONLINE,
39 : /* Online the memory to ZONE_NORMAL. */
40 : MMOP_ONLINE_KERNEL,
41 : /* Online the memory to ZONE_MOVABLE. */
42 : MMOP_ONLINE_MOVABLE,
43 : };
44 :
45 : /* Flags for add_memory() and friends to specify memory hotplug details. */
46 : typedef int __bitwise mhp_t;
47 :
48 : /* No special request */
49 : #define MHP_NONE ((__force mhp_t)0)
50 : /*
51 : * Allow merging of the added System RAM resource with adjacent,
52 : * mergeable resources. After a successful call to add_memory_resource()
53 : * with this flag set, the resource pointer must no longer be used as it
54 : * might be stale, or the resource might have changed.
55 : */
56 : #define MHP_MERGE_RESOURCE ((__force mhp_t)BIT(0))
57 :
58 : /*
59 : * Extended parameters for memory hotplug:
60 : * altmap: alternative allocator for memmap array (optional)
61 : * pgprot: page protection flags to apply to newly created page tables
62 : * (required)
63 : */
64 : struct mhp_params {
65 : struct vmem_altmap *altmap;
66 : pgprot_t pgprot;
67 : };
68 :
69 : bool mhp_range_allowed(u64 start, u64 size, bool need_mapping);
70 : struct range mhp_get_pluggable_range(bool need_mapping);
71 :
72 : /*
73 : * Zone resizing functions
74 : *
75 : * Note: any attempt to resize a zone should has pgdat_resize_lock()
76 : * zone_span_writelock() both held. This ensure the size of a zone
77 : * can't be changed while pgdat_resize_lock() held.
78 : */
79 : static inline unsigned zone_span_seqbegin(struct zone *zone)
80 : {
81 : return read_seqbegin(&zone->span_seqlock);
82 : }
83 : static inline int zone_span_seqretry(struct zone *zone, unsigned iv)
84 : {
85 : return read_seqretry(&zone->span_seqlock, iv);
86 : }
87 : static inline void zone_span_writelock(struct zone *zone)
88 : {
89 : write_seqlock(&zone->span_seqlock);
90 : }
91 : static inline void zone_span_writeunlock(struct zone *zone)
92 : {
93 : write_sequnlock(&zone->span_seqlock);
94 : }
95 : static inline void zone_seqlock_init(struct zone *zone)
96 : {
97 : seqlock_init(&zone->span_seqlock);
98 : }
99 : extern int zone_grow_free_lists(struct zone *zone, unsigned long new_nr_pages);
100 : extern int zone_grow_waitqueues(struct zone *zone, unsigned long nr_pages);
101 : extern int add_one_highpage(struct page *page, int pfn, int bad_ppro);
102 : /* VM interface that may be used by firmware interface */
103 : extern int online_pages(unsigned long pfn, unsigned long nr_pages,
104 : int online_type, int nid);
105 : extern struct zone *test_pages_in_a_zone(unsigned long start_pfn,
106 : unsigned long end_pfn);
107 : extern void __offline_isolated_pages(unsigned long start_pfn,
108 : unsigned long end_pfn);
109 :
110 : typedef void (*online_page_callback_t)(struct page *page, unsigned int order);
111 :
112 : extern void generic_online_page(struct page *page, unsigned int order);
113 : extern int set_online_page_callback(online_page_callback_t callback);
114 : extern int restore_online_page_callback(online_page_callback_t callback);
115 :
116 : extern int try_online_node(int nid);
117 :
118 : extern int arch_add_memory(int nid, u64 start, u64 size,
119 : struct mhp_params *params);
120 : extern u64 max_mem_size;
121 :
122 : extern int mhp_online_type_from_str(const char *str);
123 :
124 : /* Default online_type (MMOP_*) when new memory blocks are added. */
125 : extern int mhp_default_online_type;
126 : /* If movable_node boot option specified */
127 : extern bool movable_node_enabled;
128 : static inline bool movable_node_is_enabled(void)
129 : {
130 : return movable_node_enabled;
131 : }
132 :
133 : extern void arch_remove_memory(int nid, u64 start, u64 size,
134 : struct vmem_altmap *altmap);
135 : extern void __remove_pages(unsigned long start_pfn, unsigned long nr_pages,
136 : struct vmem_altmap *altmap);
137 :
138 : /* reasonably generic interface to expand the physical pages */
139 : extern int __add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
140 : struct mhp_params *params);
141 :
142 : #ifndef CONFIG_ARCH_HAS_ADD_PAGES
143 : static inline int add_pages(int nid, unsigned long start_pfn,
144 : unsigned long nr_pages, struct mhp_params *params)
145 : {
146 : return __add_pages(nid, start_pfn, nr_pages, params);
147 : }
148 : #else /* ARCH_HAS_ADD_PAGES */
149 : int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
150 : struct mhp_params *params);
151 : #endif /* ARCH_HAS_ADD_PAGES */
152 :
153 : #ifdef CONFIG_HAVE_ARCH_NODEDATA_EXTENSION
154 : /*
155 : * For supporting node-hotadd, we have to allocate a new pgdat.
156 : *
157 : * If an arch has generic style NODE_DATA(),
158 : * node_data[nid] = kzalloc() works well. But it depends on the architecture.
159 : *
160 : * In general, generic_alloc_nodedata() is used.
161 : * Now, arch_free_nodedata() is just defined for error path of node_hot_add.
162 : *
163 : */
164 : extern pg_data_t *arch_alloc_nodedata(int nid);
165 : extern void arch_free_nodedata(pg_data_t *pgdat);
166 : extern void arch_refresh_nodedata(int nid, pg_data_t *pgdat);
167 :
168 : #else /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */
169 :
170 : #define arch_alloc_nodedata(nid) generic_alloc_nodedata(nid)
171 : #define arch_free_nodedata(pgdat) generic_free_nodedata(pgdat)
172 :
173 : #ifdef CONFIG_NUMA
174 : /*
175 : * If ARCH_HAS_NODEDATA_EXTENSION=n, this func is used to allocate pgdat.
176 : * XXX: kmalloc_node() can't work well to get new node's memory at this time.
177 : * Because, pgdat for the new node is not allocated/initialized yet itself.
178 : * To use new node's memory, more consideration will be necessary.
179 : */
180 : #define generic_alloc_nodedata(nid) \
181 : ({ \
182 : kzalloc(sizeof(pg_data_t), GFP_KERNEL); \
183 : })
184 : /*
185 : * This definition is just for error path in node hotadd.
186 : * For node hotremove, we have to replace this.
187 : */
188 : #define generic_free_nodedata(pgdat) kfree(pgdat)
189 :
190 : extern pg_data_t *node_data[];
191 : static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
192 : {
193 : node_data[nid] = pgdat;
194 : }
195 :
196 : #else /* !CONFIG_NUMA */
197 :
198 : /* never called */
199 : static inline pg_data_t *generic_alloc_nodedata(int nid)
200 : {
201 : BUG();
202 : return NULL;
203 : }
204 : static inline void generic_free_nodedata(pg_data_t *pgdat)
205 : {
206 : }
207 : static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
208 : {
209 : }
210 : #endif /* CONFIG_NUMA */
211 : #endif /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */
212 :
213 : #ifdef CONFIG_HAVE_BOOTMEM_INFO_NODE
214 : extern void __init register_page_bootmem_info_node(struct pglist_data *pgdat);
215 : #else
216 : static inline void register_page_bootmem_info_node(struct pglist_data *pgdat)
217 : {
218 : }
219 : #endif
220 : extern void put_page_bootmem(struct page *page);
221 : extern void get_page_bootmem(unsigned long ingo, struct page *page,
222 : unsigned long type);
223 :
224 : void get_online_mems(void);
225 : void put_online_mems(void);
226 :
227 : void mem_hotplug_begin(void);
228 : void mem_hotplug_done(void);
229 :
230 : #else /* ! CONFIG_MEMORY_HOTPLUG */
231 : #define pfn_to_online_page(pfn) \
232 : ({ \
233 : struct page *___page = NULL; \
234 : if (pfn_valid(pfn)) \
235 : ___page = pfn_to_page(pfn); \
236 : ___page; \
237 : })
238 :
239 290654 : static inline unsigned zone_span_seqbegin(struct zone *zone)
240 : {
241 290654 : return 0;
242 : }
243 0 : static inline int zone_span_seqretry(struct zone *zone, unsigned iv)
244 : {
245 0 : return 0;
246 : }
247 : static inline void zone_span_writelock(struct zone *zone) {}
248 : static inline void zone_span_writeunlock(struct zone *zone) {}
249 3 : static inline void zone_seqlock_init(struct zone *zone) {}
250 :
251 1 : static inline void register_page_bootmem_info_node(struct pglist_data *pgdat)
252 : {
253 1 : }
254 :
255 3 : static inline int try_online_node(int nid)
256 : {
257 3 : return 0;
258 : }
259 :
260 0 : static inline void get_online_mems(void) {}
261 0 : static inline void put_online_mems(void) {}
262 :
263 : static inline void mem_hotplug_begin(void) {}
264 : static inline void mem_hotplug_done(void) {}
265 :
266 949 : static inline bool movable_node_is_enabled(void)
267 : {
268 949 : return false;
269 : }
270 : #endif /* ! CONFIG_MEMORY_HOTPLUG */
271 :
272 : /*
273 : * Keep this declaration outside CONFIG_MEMORY_HOTPLUG as some
274 : * platforms might override and use arch_get_mappable_range()
275 : * for internal non memory hotplug purposes.
276 : */
277 : struct range arch_get_mappable_range(void);
278 :
279 : #if defined(CONFIG_MEMORY_HOTPLUG) || defined(CONFIG_DEFERRED_STRUCT_PAGE_INIT)
280 : /*
281 : * pgdat resizing functions
282 : */
283 : static inline
284 : void pgdat_resize_lock(struct pglist_data *pgdat, unsigned long *flags)
285 : {
286 : spin_lock_irqsave(&pgdat->node_size_lock, *flags);
287 : }
288 : static inline
289 : void pgdat_resize_unlock(struct pglist_data *pgdat, unsigned long *flags)
290 : {
291 : spin_unlock_irqrestore(&pgdat->node_size_lock, *flags);
292 : }
293 : static inline
294 : void pgdat_resize_init(struct pglist_data *pgdat)
295 : {
296 : spin_lock_init(&pgdat->node_size_lock);
297 : }
298 : #else /* !(CONFIG_MEMORY_HOTPLUG || CONFIG_DEFERRED_STRUCT_PAGE_INIT) */
299 : /*
300 : * Stub functions for when hotplug is off
301 : */
302 : static inline void pgdat_resize_lock(struct pglist_data *p, unsigned long *f) {}
303 : static inline void pgdat_resize_unlock(struct pglist_data *p, unsigned long *f) {}
304 1 : static inline void pgdat_resize_init(struct pglist_data *pgdat) {}
305 : #endif /* !(CONFIG_MEMORY_HOTPLUG || CONFIG_DEFERRED_STRUCT_PAGE_INIT) */
306 :
307 : #ifdef CONFIG_MEMORY_HOTREMOVE
308 :
309 : extern void try_offline_node(int nid);
310 : extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
311 : extern int remove_memory(int nid, u64 start, u64 size);
312 : extern void __remove_memory(int nid, u64 start, u64 size);
313 : extern int offline_and_remove_memory(int nid, u64 start, u64 size);
314 :
315 : #else
316 : static inline void try_offline_node(int nid) {}
317 :
318 : static inline int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
319 : {
320 : return -EINVAL;
321 : }
322 :
323 : static inline int remove_memory(int nid, u64 start, u64 size)
324 : {
325 : return -EBUSY;
326 : }
327 :
328 : static inline void __remove_memory(int nid, u64 start, u64 size) {}
329 : #endif /* CONFIG_MEMORY_HOTREMOVE */
330 :
331 : extern void set_zone_contiguous(struct zone *zone);
332 : extern void clear_zone_contiguous(struct zone *zone);
333 :
334 : #ifdef CONFIG_MEMORY_HOTPLUG
335 : extern void __ref free_area_init_core_hotplug(int nid);
336 : extern int __add_memory(int nid, u64 start, u64 size, mhp_t mhp_flags);
337 : extern int add_memory(int nid, u64 start, u64 size, mhp_t mhp_flags);
338 : extern int add_memory_resource(int nid, struct resource *resource,
339 : mhp_t mhp_flags);
340 : extern int add_memory_driver_managed(int nid, u64 start, u64 size,
341 : const char *resource_name,
342 : mhp_t mhp_flags);
343 : extern void move_pfn_range_to_zone(struct zone *zone, unsigned long start_pfn,
344 : unsigned long nr_pages,
345 : struct vmem_altmap *altmap, int migratetype);
346 : extern void remove_pfn_range_from_zone(struct zone *zone,
347 : unsigned long start_pfn,
348 : unsigned long nr_pages);
349 : extern bool is_memblock_offlined(struct memory_block *mem);
350 : extern int sparse_add_section(int nid, unsigned long pfn,
351 : unsigned long nr_pages, struct vmem_altmap *altmap);
352 : extern void sparse_remove_section(struct mem_section *ms,
353 : unsigned long pfn, unsigned long nr_pages,
354 : unsigned long map_offset, struct vmem_altmap *altmap);
355 : extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map,
356 : unsigned long pnum);
357 : extern struct zone *zone_for_pfn_range(int online_type, int nid, unsigned start_pfn,
358 : unsigned long nr_pages);
359 : extern int arch_create_linear_mapping(int nid, u64 start, u64 size,
360 : struct mhp_params *params);
361 : void arch_remove_linear_mapping(u64 start, u64 size);
362 : #endif /* CONFIG_MEMORY_HOTPLUG */
363 :
364 : #endif /* __LINUX_MEMORY_HOTPLUG_H */
|