memory_hotplug.h 11.1 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0 */
2 3 4 5 6
#ifndef __LINUX_MEMORY_HOTPLUG_H
#define __LINUX_MEMORY_HOTPLUG_H

#include <linux/mmzone.h>
#include <linux/spinlock.h>
7
#include <linux/notifier.h>
8
#include <linux/bug.h>
9

10 11 12
struct page;
struct zone;
struct pglist_data;
13
struct mem_section;
14
struct memory_block;
15
struct memory_group;
16
struct resource;
17
struct vmem_altmap;
18
struct dev_pagemap;
19

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
#ifdef CONFIG_HAVE_ARCH_NODEDATA_EXTENSION
/*
 * For supporting node-hotadd, we have to allocate a new pgdat.
 *
 * If an arch has generic style NODE_DATA(),
 * node_data[nid] = kzalloc() works well. But it depends on the architecture.
 *
 * In general, generic_alloc_nodedata() is used.
 *
 */
extern pg_data_t *arch_alloc_nodedata(int nid);
extern void arch_refresh_nodedata(int nid, pg_data_t *pgdat);

#else /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */

#define arch_alloc_nodedata(nid)	generic_alloc_nodedata(nid)

#ifdef CONFIG_NUMA
/*
 * XXX: node aware allocation can't work well to get new node's memory at this time.
 *	Because, pgdat for the new node is not allocated/initialized yet itself.
 *	To use new node's memory, more consideration will be necessary.
 */
#define generic_alloc_nodedata(nid)				\
({								\
45
	memblock_alloc(sizeof(*pgdat), SMP_CACHE_BYTES);	\
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
})
/*
 * This definition is just for error path in node hotadd.
 * For node hotremove, we have to replace this.
 */
#define generic_free_nodedata(pgdat)	kfree(pgdat)

extern pg_data_t *node_data[];
static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
{
	node_data[nid] = pgdat;
}

#else /* !CONFIG_NUMA */

/* never called */
static inline pg_data_t *generic_alloc_nodedata(int nid)
{
	BUG();
	return NULL;
}
static inline void generic_free_nodedata(pg_data_t *pgdat)
{
}
static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
{
}
#endif /* CONFIG_NUMA */
#endif /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */

76
#ifdef CONFIG_MEMORY_HOTPLUG
77
struct page *pfn_to_online_page(unsigned long pfn);
78

79
/* Types for control the zone type of onlined and offlined memory */
80
enum {
81
	/* Offline the memory. */
82
	MMOP_OFFLINE = 0,
83 84 85
	/* Online the memory. Zone depends, see default_zone_for_pfn(). */
	MMOP_ONLINE,
	/* Online the memory to ZONE_NORMAL. */
86
	MMOP_ONLINE_KERNEL,
87
	/* Online the memory to ZONE_MOVABLE. */
88
	MMOP_ONLINE_MOVABLE,
89 90
};

91 92 93 94 95
/* Flags for add_memory() and friends to specify memory hotplug details. */
typedef int __bitwise mhp_t;

/* No special request */
#define MHP_NONE		((__force mhp_t)0)
96 97 98 99 100 101
/*
 * Allow merging of the added System RAM resource with adjacent,
 * mergeable resources. After a successful call to add_memory_resource()
 * with this flag set, the resource pointer must no longer be used as it
 * might be stale, or the resource might have changed.
 */
102
#define MHP_MERGE_RESOURCE	((__force mhp_t)BIT(0))
103

104 105 106 107 108 109 110
/*
 * We want memmap (struct page array) to be self contained.
 * To do so, we will use the beginning of the hot-added range to build
 * the page tables for the memmap array that describes the entire range.
 * Only selected architectures support it with SPARSE_VMEMMAP.
 */
#define MHP_MEMMAP_ON_MEMORY   ((__force mhp_t)BIT(1))
111 112 113 114 115
/*
 * The nid field specifies a memory group id (mgid) instead. The memory group
 * implies the node id (nid).
 */
#define MHP_NID_IS_MGID		((__force mhp_t)BIT(2))
116

117
/*
118 119
 * Extended parameters for memory hotplug:
 * altmap: alternative allocator for memmap array (optional)
120 121
 * pgprot: page protection flags to apply to newly created page tables
 *	(required)
122
 */
123
struct mhp_params {
124
	struct vmem_altmap *altmap;
125
	pgprot_t pgprot;
126
	struct dev_pagemap *pgmap;
127 128
};

129 130 131
bool mhp_range_allowed(u64 start, u64 size, bool need_mapping);
struct range mhp_get_pluggable_range(bool need_mapping);

132 133
/*
 * Zone resizing functions
134 135 136 137
 *
 * Note: any attempt to resize a zone should has pgdat_resize_lock()
 * zone_span_writelock() both held. This ensure the size of a zone
 * can't be changed while pgdat_resize_lock() held.
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
 */
static inline unsigned zone_span_seqbegin(struct zone *zone)
{
	return read_seqbegin(&zone->span_seqlock);
}
static inline int zone_span_seqretry(struct zone *zone, unsigned iv)
{
	return read_seqretry(&zone->span_seqlock, iv);
}
static inline void zone_span_writelock(struct zone *zone)
{
	write_seqlock(&zone->span_seqlock);
}
static inline void zone_span_writeunlock(struct zone *zone)
{
	write_sequnlock(&zone->span_seqlock);
}
static inline void zone_seqlock_init(struct zone *zone)
{
	seqlock_init(&zone->span_seqlock);
}
159 160 161
extern void adjust_present_page_count(struct page *page,
				      struct memory_group *group,
				      long nr_pages);
162
/* VM interface that may be used by firmware interface */
163 164 165
extern int mhp_init_memmap_on_memory(unsigned long pfn, unsigned long nr_pages,
				     struct zone *zone);
extern void mhp_deinit_memmap_on_memory(unsigned long pfn, unsigned long nr_pages);
166
extern int online_pages(unsigned long pfn, unsigned long nr_pages,
167
			struct zone *zone, struct memory_group *group);
168 169
extern void __offline_isolated_pages(unsigned long start_pfn,
				     unsigned long end_pfn);
170

171
typedef void (*online_page_callback_t)(struct page *page, unsigned int order);
172

173
extern void generic_online_page(struct page *page, unsigned int order);
174 175 176
extern int set_online_page_callback(online_page_callback_t callback);
extern int restore_online_page_callback(online_page_callback_t callback);

177 178
extern int try_online_node(int nid);

179
extern int arch_add_memory(int nid, u64 start, u64 size,
180
			   struct mhp_params *params);
181 182
extern u64 max_mem_size;

183
extern int mhp_online_type_from_str(const char *str);
184

185
/* Default online_type (MMOP_*) when new memory blocks are added. */
186
extern int mhp_default_online_type;
187 188 189 190 191 192
/* If movable_node boot option specified */
extern bool movable_node_enabled;
static inline bool movable_node_is_enabled(void)
{
	return movable_node_enabled;
}
193

194
extern void arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap);
195 196
extern void __remove_pages(unsigned long start_pfn, unsigned long nr_pages,
			   struct vmem_altmap *altmap);
197

198
/* reasonably generic interface to expand the physical pages */
199
extern int __add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
200
		       struct mhp_params *params);
201

202 203
#ifndef CONFIG_ARCH_HAS_ADD_PAGES
static inline int add_pages(int nid, unsigned long start_pfn,
204
		unsigned long nr_pages, struct mhp_params *params)
205
{
206
	return __add_pages(nid, start_pfn, nr_pages, params);
207 208
}
#else /* ARCH_HAS_ADD_PAGES */
209
int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
210
	      struct mhp_params *params);
211 212
#endif /* ARCH_HAS_ADD_PAGES */

213 214
void get_online_mems(void);
void put_online_mems(void);
215

216 217 218
void mem_hotplug_begin(void);
void mem_hotplug_done(void);

219
#else /* ! CONFIG_MEMORY_HOTPLUG */
220 221 222 223 224 225 226 227
#define pfn_to_online_page(pfn)			\
({						\
	struct page *___page = NULL;		\
	if (pfn_valid(pfn))			\
		___page = pfn_to_page(pfn);	\
	___page;				\
 })

228 229 230 231 232 233 234 235 236 237 238
static inline unsigned zone_span_seqbegin(struct zone *zone)
{
	return 0;
}
static inline int zone_span_seqretry(struct zone *zone, unsigned iv)
{
	return 0;
}
static inline void zone_span_writelock(struct zone *zone) {}
static inline void zone_span_writeunlock(struct zone *zone) {}
static inline void zone_seqlock_init(struct zone *zone) {}
239

240 241 242 243 244
static inline int try_online_node(int nid)
{
	return 0;
}

245 246
static inline void get_online_mems(void) {}
static inline void put_online_mems(void) {}
247

248 249 250
static inline void mem_hotplug_begin(void) {}
static inline void mem_hotplug_done(void) {}

251 252 253 254
static inline bool movable_node_is_enabled(void)
{
	return false;
}
255
#endif /* ! CONFIG_MEMORY_HOTPLUG */
256

257 258 259 260 261 262 263
/*
 * Keep this declaration outside CONFIG_MEMORY_HOTPLUG as some
 * platforms might override and use arch_get_mappable_range()
 * for internal non memory hotplug purposes.
 */
struct range arch_get_mappable_range(void);

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
#if defined(CONFIG_MEMORY_HOTPLUG) || defined(CONFIG_DEFERRED_STRUCT_PAGE_INIT)
/*
 * pgdat resizing functions
 */
static inline
void pgdat_resize_lock(struct pglist_data *pgdat, unsigned long *flags)
{
	spin_lock_irqsave(&pgdat->node_size_lock, *flags);
}
static inline
void pgdat_resize_unlock(struct pglist_data *pgdat, unsigned long *flags)
{
	spin_unlock_irqrestore(&pgdat->node_size_lock, *flags);
}
static inline
void pgdat_resize_init(struct pglist_data *pgdat)
{
	spin_lock_init(&pgdat->node_size_lock);
}
#else /* !(CONFIG_MEMORY_HOTPLUG || CONFIG_DEFERRED_STRUCT_PAGE_INIT) */
/*
 * Stub functions for when hotplug is off
 */
static inline void pgdat_resize_lock(struct pglist_data *p, unsigned long *f) {}
static inline void pgdat_resize_unlock(struct pglist_data *p, unsigned long *f) {}
static inline void pgdat_resize_init(struct pglist_data *pgdat) {}
#endif /* !(CONFIG_MEMORY_HOTPLUG || CONFIG_DEFERRED_STRUCT_PAGE_INIT) */

292 293
#ifdef CONFIG_MEMORY_HOTREMOVE

294
extern void try_offline_node(int nid);
295
extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages,
296
			 struct zone *zone, struct memory_group *group);
297 298 299
extern int remove_memory(u64 start, u64 size);
extern void __remove_memory(u64 start, u64 size);
extern int offline_and_remove_memory(u64 start, u64 size);
300 301

#else
302
static inline void try_offline_node(int nid) {}
303

304
static inline int offline_pages(unsigned long start_pfn, unsigned long nr_pages,
305
				struct zone *zone, struct memory_group *group)
306 307 308 309
{
	return -EINVAL;
}

310
static inline int remove_memory(u64 start, u64 size)
311 312 313 314
{
	return -EBUSY;
}

315
static inline void __remove_memory(u64 start, u64 size) {}
316 317
#endif /* CONFIG_MEMORY_HOTREMOVE */

318 319 320
extern void set_zone_contiguous(struct zone *zone);
extern void clear_zone_contiguous(struct zone *zone);

321
#ifdef CONFIG_MEMORY_HOTPLUG
322
extern void __ref free_area_init_core_hotplug(struct pglist_data *pgdat);
323 324 325 326
extern int __add_memory(int nid, u64 start, u64 size, mhp_t mhp_flags);
extern int add_memory(int nid, u64 start, u64 size, mhp_t mhp_flags);
extern int add_memory_resource(int nid, struct resource *resource,
			       mhp_t mhp_flags);
327
extern int add_memory_driver_managed(int nid, u64 start, u64 size,
328 329
				     const char *resource_name,
				     mhp_t mhp_flags);
330
extern void move_pfn_range_to_zone(struct zone *zone, unsigned long start_pfn,
331 332
				   unsigned long nr_pages,
				   struct vmem_altmap *altmap, int migratetype);
333 334 335
extern void remove_pfn_range_from_zone(struct zone *zone,
				       unsigned long start_pfn,
				       unsigned long nr_pages);
336
extern bool is_memblock_offlined(struct memory_block *mem);
337
extern int sparse_add_section(int nid, unsigned long pfn,
338 339
		unsigned long nr_pages, struct vmem_altmap *altmap,
		struct dev_pagemap *pgmap);
340
extern void sparse_remove_section(struct mem_section *ms,
341
		unsigned long pfn, unsigned long nr_pages,
342
		unsigned long map_offset, struct vmem_altmap *altmap);
343 344
extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map,
					  unsigned long pnum);
345
extern struct zone *zone_for_pfn_range(int online_type, int nid,
346 347
		struct memory_group *group, unsigned long start_pfn,
		unsigned long nr_pages);
348 349 350
extern int arch_create_linear_mapping(int nid, u64 start, u64 size,
				      struct mhp_params *params);
void arch_remove_linear_mapping(u64 start, u64 size);
351
extern bool mhp_supports_memmap_on_memory(unsigned long size);
352 353
#endif /* CONFIG_MEMORY_HOTPLUG */

354 355 356 357 358 359 360 361 362
#ifdef CONFIG_MHP_MEMMAP_ON_MEMORY
bool mhp_memmap_on_memory(void);
#else
static inline bool mhp_memmap_on_memory(void)
{
	return false;
}
#endif

363
#endif /* __LINUX_MEMORY_HOTPLUG_H */