mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge branch 'kho-scratch' into next
This commit is contained in:
@@ -14334,6 +14334,7 @@ S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git
|
||||
F: Documentation/admin-guide/mm/kho.rst
|
||||
F: Documentation/core-api/kho/*
|
||||
F: include/asm-generic/kexec_handover.h
|
||||
F: include/linux/kexec_handover.h
|
||||
F: include/linux/kho/
|
||||
F: include/linux/kho_block.h
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <asm/setup.h> /* For COMMAND_LINE_SIZE */
|
||||
#undef _SETUP
|
||||
|
||||
#include <asm/kexec_handover.h>
|
||||
|
||||
extern unsigned long get_cmd_line_ptr(void);
|
||||
|
||||
/* Simplified build-specific string for starting entropy. */
|
||||
|
||||
@@ -15,3 +15,4 @@ generic-y += fprobe.h
|
||||
generic-y += mcs_spinlock.h
|
||||
generic-y += mmzone.h
|
||||
generic-y += ring_buffer.h
|
||||
generic-y += kexec_handover.h
|
||||
|
||||
@@ -69,8 +69,6 @@ extern void x86_ce4100_early_setup(void);
|
||||
static inline void x86_ce4100_early_setup(void) { }
|
||||
#endif
|
||||
|
||||
#include <linux/kexec_handover.h>
|
||||
|
||||
#ifndef _SETUP
|
||||
|
||||
#include <asm/espfix.h>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/init_ohci1394_dma.h>
|
||||
#include <linux/initrd.h>
|
||||
#include <linux/iscsi_ibft.h>
|
||||
#include <linux/kexec_handover.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/panic_notifier.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __ASM_GENERIC_KEXEC_HANDOVER_H
|
||||
#define __ASM_GENERIC_KEXEC_HANDOVER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct kho_scratch {
|
||||
phys_addr_t addr;
|
||||
phys_addr_t size;
|
||||
};
|
||||
|
||||
#endif /* __ASM_GENERIC_KEXEC_HANDOVER_H */
|
||||
@@ -5,11 +5,8 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct kho_scratch {
|
||||
phys_addr_t addr;
|
||||
phys_addr_t size;
|
||||
};
|
||||
#include <linux/mmzone.h>
|
||||
#include <asm-generic/kexec_handover.h>
|
||||
|
||||
struct kho_vmalloc;
|
||||
|
||||
@@ -37,9 +34,20 @@ void kho_remove_subtree(void *blob);
|
||||
int kho_retrieve_subtree(const char *name, phys_addr_t *phys, size_t *size);
|
||||
|
||||
void kho_memory_init(void);
|
||||
void kho_memory_init_early(void);
|
||||
|
||||
void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys,
|
||||
u64 scratch_len);
|
||||
|
||||
bool kho_scratch_overlap(phys_addr_t phys, size_t size);
|
||||
|
||||
static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
|
||||
enum migratetype mt)
|
||||
{
|
||||
if (kho_scratch_overlap(PFN_PHYS(pfn), pageblock_nr_pages << PAGE_SHIFT))
|
||||
return MIGRATE_CMA;
|
||||
return mt;
|
||||
}
|
||||
#else
|
||||
static inline bool kho_is_enabled(void)
|
||||
{
|
||||
@@ -112,10 +120,23 @@ static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys,
|
||||
|
||||
static inline void kho_memory_init(void) { }
|
||||
|
||||
static inline void kho_memory_init_early(void) { }
|
||||
|
||||
static inline void kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
|
||||
phys_addr_t scratch_phys, u64 scratch_len)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
|
||||
enum migratetype mt)
|
||||
{
|
||||
return mt;
|
||||
}
|
||||
#endif /* CONFIG_KEXEC_HANDOVER */
|
||||
|
||||
#endif /* LINUX_KEXEC_HANDOVER_H */
|
||||
|
||||
@@ -257,11 +257,8 @@ struct kho_vmalloc {
|
||||
* memory. These constants govern the indexing, sizing, and depth of the tree.
|
||||
*/
|
||||
enum kho_radix_consts {
|
||||
/*
|
||||
* The bit position of the order bit (and also the length of the
|
||||
* shifted physical address) for an order-0 page.
|
||||
*/
|
||||
KHO_ORDER_0_LOG2 = 64 - PAGE_SHIFT,
|
||||
/* Need to store the PFN, plus one bit for order. */
|
||||
KHO_RADIX_KEY_WIDTH = 64 - PAGE_SHIFT + 1,
|
||||
|
||||
/* Size of the table in kho_radix_node, in log2 */
|
||||
KHO_TABLE_SIZE_LOG2 = const_ilog2(PAGE_SIZE / sizeof(phys_addr_t)),
|
||||
@@ -274,7 +271,7 @@ enum kho_radix_consts {
|
||||
* and 1 bitmap level.
|
||||
*/
|
||||
KHO_TREE_MAX_DEPTH =
|
||||
DIV_ROUND_UP(KHO_ORDER_0_LOG2 - KHO_BITMAP_SIZE_LOG2 + 1,
|
||||
DIV_ROUND_UP(KHO_RADIX_KEY_WIDTH - KHO_BITMAP_SIZE_LOG2,
|
||||
KHO_TABLE_SIZE_LOG2) + 1,
|
||||
};
|
||||
|
||||
|
||||
@@ -34,37 +34,53 @@ struct kho_radix_tree {
|
||||
struct mutex lock; /* protects the tree's structure and root pointer */
|
||||
};
|
||||
|
||||
typedef int (*kho_radix_tree_walk_callback_t)(phys_addr_t phys,
|
||||
unsigned int order);
|
||||
/**
|
||||
* struct kho_radix_walk_cb - Callbacks for KHO radix tree walk.
|
||||
* @leaf: Called on each present key in the radix tree.
|
||||
* @node: Called on each node of the radix tree itself. Receives the
|
||||
* physical address of the page containing the node.
|
||||
*
|
||||
* For each callback, a return value of 0 continues the walk and a non-zero
|
||||
* return value is directly returned to the caller.
|
||||
*/
|
||||
struct kho_radix_walk_cb {
|
||||
int (*leaf)(unsigned long key, void *data);
|
||||
int (*node)(phys_addr_t phys, void *data);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_KEXEC_HANDOVER
|
||||
|
||||
int kho_radix_add_page(struct kho_radix_tree *tree, unsigned long pfn,
|
||||
unsigned int order);
|
||||
|
||||
void kho_radix_del_page(struct kho_radix_tree *tree, unsigned long pfn,
|
||||
unsigned int order);
|
||||
|
||||
int kho_radix_add_key(struct kho_radix_tree *tree, unsigned long key);
|
||||
void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key);
|
||||
int kho_radix_walk_tree(struct kho_radix_tree *tree,
|
||||
kho_radix_tree_walk_callback_t cb);
|
||||
const struct kho_radix_walk_cb *cb, void *data);
|
||||
int kho_radix_init_tree(struct kho_radix_tree *tree, struct kho_radix_node *root);
|
||||
void kho_radix_destroy_tree(struct kho_radix_tree *tree);
|
||||
|
||||
#else /* #ifdef CONFIG_KEXEC_HANDOVER */
|
||||
|
||||
static inline int kho_radix_add_page(struct kho_radix_tree *tree, long pfn,
|
||||
unsigned int order)
|
||||
static inline int kho_radix_add_key(struct kho_radix_tree *tree, unsigned long key)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void kho_radix_del_page(struct kho_radix_tree *tree,
|
||||
unsigned long pfn, unsigned int order) { }
|
||||
static inline void kho_radix_del_key(struct kho_radix_tree *tree,
|
||||
unsigned long key) { }
|
||||
|
||||
static inline int kho_radix_walk_tree(struct kho_radix_tree *tree,
|
||||
kho_radix_tree_walk_callback_t cb)
|
||||
const struct kho_radix_walk_cb *cb, void *data)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int kho_radix_init_tree(struct kho_radix_tree *tree,
|
||||
struct kho_radix_node *root)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void kho_radix_destroy_tree(struct kho_radix_tree *tree) { }
|
||||
|
||||
#endif /* #ifdef CONFIG_KEXEC_HANDOVER */
|
||||
|
||||
#endif /* _LINUX_KHO_RADIX_TREE_H */
|
||||
|
||||
@@ -51,6 +51,7 @@ extern unsigned long long max_possible_pfn;
|
||||
* memory reservations yet, so we get scratch memory from the previous
|
||||
* kernel that we know is good to use. It is the only memory that
|
||||
* allocations may happen from in this phase.
|
||||
* @MEMBLOCK_RSRV_HUGETLB: memory is reserved for hugetlb pages
|
||||
*/
|
||||
enum memblock_flags {
|
||||
MEMBLOCK_NONE = 0x0, /* No special request */
|
||||
@@ -61,6 +62,7 @@ enum memblock_flags {
|
||||
MEMBLOCK_RSRV_NOINIT = 0x10, /* don't initialize struct pages */
|
||||
MEMBLOCK_RSRV_KERN = 0x20, /* memory reserved for kernel use */
|
||||
MEMBLOCK_KHO_SCRATCH = 0x40, /* scratch memory for kexec handover */
|
||||
MEMBLOCK_RSRV_HUGETLB = 0x80, /* memory reserved for hugetlb pages */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -420,6 +422,7 @@ void *memblock_alloc_try_nid_raw(phys_addr_t size, phys_addr_t align,
|
||||
void *memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align,
|
||||
phys_addr_t min_addr, phys_addr_t max_addr,
|
||||
int nid);
|
||||
void *memblock_alloc_hugetlb(phys_addr_t size, int nid, bool exact_nid);
|
||||
|
||||
static __always_inline void *memblock_alloc(phys_addr_t size, phys_addr_t align)
|
||||
{
|
||||
@@ -484,6 +487,7 @@ static inline __init_memblock bool memblock_bottom_up(void)
|
||||
phys_addr_t memblock_phys_mem_size(void);
|
||||
phys_addr_t memblock_reserved_size(void);
|
||||
phys_addr_t memblock_reserved_kern_size(phys_addr_t limit, int nid);
|
||||
phys_addr_t memblock_reserved_hugetlb_size(phys_addr_t limit, int nid);
|
||||
unsigned long memblock_estimated_nr_free_pages(void);
|
||||
phys_addr_t memblock_start_of_DRAM(void);
|
||||
phys_addr_t memblock_end_of_DRAM(void);
|
||||
@@ -613,28 +617,9 @@ static inline void memtest_report_meminfo(struct seq_file *m) { }
|
||||
#ifdef CONFIG_MEMBLOCK_KHO_SCRATCH
|
||||
void memblock_set_kho_scratch_only(void);
|
||||
void memblock_clear_kho_scratch_only(void);
|
||||
bool memblock_is_kho_scratch_memory(phys_addr_t addr);
|
||||
|
||||
static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
|
||||
enum migratetype mt)
|
||||
{
|
||||
if (memblock_is_kho_scratch_memory(PFN_PHYS(pfn)))
|
||||
return MIGRATE_CMA;
|
||||
return mt;
|
||||
}
|
||||
#else
|
||||
static inline void memblock_set_kho_scratch_only(void) { }
|
||||
static inline void memblock_clear_kho_scratch_only(void) { }
|
||||
static inline bool memblock_is_kho_scratch_memory(phys_addr_t addr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
|
||||
enum migratetype mt)
|
||||
{
|
||||
return mt;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_MEMBLOCK_H */
|
||||
|
||||
@@ -8,7 +8,6 @@ luo-y := \
|
||||
luo_session.o
|
||||
|
||||
obj-$(CONFIG_KEXEC_HANDOVER) += kexec_handover.o
|
||||
obj-$(CONFIG_KEXEC_HANDOVER_DEBUG) += kexec_handover_debug.o
|
||||
obj-$(CONFIG_KEXEC_HANDOVER_DEBUGFS) += kexec_handover_debugfs.o
|
||||
|
||||
obj-$(CONFIG_LIVEUPDATE) += luo.o
|
||||
|
||||
+407
-119
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* kexec_handover_debug.c - kexec handover optional debug functionality
|
||||
* Copyright (C) 2025 Google LLC, Pasha Tatashin <pasha.tatashin@soleen.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "KHO: " fmt
|
||||
|
||||
#include "kexec_handover_internal.h"
|
||||
|
||||
bool kho_scratch_overlap(phys_addr_t phys, size_t size)
|
||||
{
|
||||
phys_addr_t scratch_start, scratch_end;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < kho_scratch_cnt; i++) {
|
||||
scratch_start = kho_scratch[i].addr;
|
||||
scratch_end = kho_scratch[i].addr + kho_scratch[i].size;
|
||||
|
||||
if (phys < scratch_end && (phys + size) > scratch_start)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -41,13 +41,4 @@ static inline void kho_debugfs_blob_remove(struct kho_debugfs *dbg,
|
||||
void *blob) { }
|
||||
#endif /* CONFIG_KEXEC_HANDOVER_DEBUGFS */
|
||||
|
||||
#ifdef CONFIG_KEXEC_HANDOVER_DEBUG
|
||||
bool kho_scratch_overlap(phys_addr_t phys, size_t size);
|
||||
#else
|
||||
static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_KEXEC_HANDOVER_DEBUG */
|
||||
|
||||
#endif /* LINUX_KEXEC_HANDOVER_INTERNAL_H */
|
||||
|
||||
+7
-15
@@ -3033,29 +3033,21 @@ static __init void *alloc_bootmem(struct hstate *h, int nid, bool node_exact)
|
||||
if (hugetlb_early_cma(h))
|
||||
m = hugetlb_cma_alloc_bootmem(h, &listnode, node_exact);
|
||||
else {
|
||||
if (node_exact)
|
||||
m = memblock_alloc_exact_nid_raw(huge_page_size(h),
|
||||
huge_page_size(h), 0,
|
||||
MEMBLOCK_ALLOC_ACCESSIBLE, nid);
|
||||
else {
|
||||
m = memblock_alloc_try_nid_raw(huge_page_size(h),
|
||||
huge_page_size(h), 0,
|
||||
MEMBLOCK_ALLOC_ACCESSIBLE, nid);
|
||||
m = memblock_alloc_hugetlb(huge_page_size(h), nid, node_exact);
|
||||
if (m) {
|
||||
m->flags = 0;
|
||||
m->cma = NULL;
|
||||
|
||||
/*
|
||||
* For pre-HVO to work correctly, pages need to be on
|
||||
* the list for the node they were actually allocated
|
||||
* from. That node may be different in the case of
|
||||
* fallback by memblock_alloc_try_nid_raw. So,
|
||||
* fallback by memblock_alloc_hugetlb_bootmem. So,
|
||||
* extract the actual node first.
|
||||
*/
|
||||
if (m)
|
||||
if (!node_exact)
|
||||
listnode = early_pfn_to_nid(PHYS_PFN(__pa(m)));
|
||||
}
|
||||
|
||||
if (m) {
|
||||
m->flags = 0;
|
||||
m->cma = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (m) {
|
||||
|
||||
+112
-34
@@ -19,11 +19,9 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/string_helpers.h>
|
||||
|
||||
#ifdef CONFIG_KEXEC_HANDOVER
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/kexec_handover.h>
|
||||
#include <linux/kho/abi/memblock.h>
|
||||
#endif /* CONFIG_KEXEC_HANDOVER */
|
||||
|
||||
#include <asm/sections.h>
|
||||
#include <linux/io.h>
|
||||
@@ -1506,6 +1504,32 @@ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void memblock_prep_allocation(phys_addr_t start, phys_addr_t size,
|
||||
bool kmemleak_trace)
|
||||
{
|
||||
/*
|
||||
* Skip kmemleak for those places like kasan_init() and
|
||||
* early_pgtable_alloc() due to high volume.
|
||||
*/
|
||||
if (kmemleak_trace)
|
||||
/*
|
||||
* Memblock allocated blocks are never reported as
|
||||
* leaks. This is because many of these blocks are
|
||||
* only referred via the physical address which is
|
||||
* not looked up by kmemleak.
|
||||
*/
|
||||
kmemleak_alloc_phys(start, size, 0);
|
||||
|
||||
/*
|
||||
* Some Virtual Machine platforms, such as Intel TDX or AMD SEV-SNP,
|
||||
* require memory to be accepted before it can be used by the
|
||||
* guest.
|
||||
*
|
||||
* Accept the memory of the allocated buffer.
|
||||
*/
|
||||
accept_memory(start, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* memblock_alloc_range_nid - allocate boot memory block
|
||||
* @size: size of memory block to be allocated in bytes
|
||||
@@ -1580,28 +1604,7 @@ again:
|
||||
return 0;
|
||||
|
||||
done:
|
||||
/*
|
||||
* Skip kmemleak for those places like kasan_init() and
|
||||
* early_pgtable_alloc() due to high volume.
|
||||
*/
|
||||
if (end != MEMBLOCK_ALLOC_NOLEAKTRACE)
|
||||
/*
|
||||
* Memblock allocated blocks are never reported as
|
||||
* leaks. This is because many of these blocks are
|
||||
* only referred via the physical address which is
|
||||
* not looked up by kmemleak.
|
||||
*/
|
||||
kmemleak_alloc_phys(found, size, 0);
|
||||
|
||||
/*
|
||||
* Some Virtual Machine platforms, such as Intel TDX or AMD SEV-SNP,
|
||||
* require memory to be accepted before it can be used by the
|
||||
* guest.
|
||||
*
|
||||
* Accept the memory of the allocated buffer.
|
||||
*/
|
||||
accept_memory(found, size);
|
||||
|
||||
memblock_prep_allocation(found, size, end != MEMBLOCK_ALLOC_NOLEAKTRACE);
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -1756,6 +1759,69 @@ void * __init memblock_alloc_try_nid_raw(
|
||||
false);
|
||||
}
|
||||
|
||||
/**
|
||||
* memblock_alloc_hugetlb - allocate boot memory for HugeTLB pages
|
||||
* @size: size of the memory to be allocated in bytes
|
||||
* @nid: nid of the free memory to find, %NUMA_NO_NODE for any node
|
||||
* @exact_nid: only allocate from the specified nid. If %false, the specified
|
||||
* nid is tried first, and then all nodes are tried as fallback.
|
||||
*
|
||||
* HugeTLB pages are always aligned by their size, so the alignment matches
|
||||
* @size. Since the memory is for userspace, mirrored memory is not used. The
|
||||
* memory is not zeroed. Does not panic if request cannot be satisfied.
|
||||
*
|
||||
* Return:
|
||||
* Virtual address of allocated memory block on success, %NULL on failure.
|
||||
*/
|
||||
void * __init memblock_alloc_hugetlb(phys_addr_t size, int nid, bool exact_nid)
|
||||
{
|
||||
enum memblock_flags flags = choose_memblock_flags();
|
||||
phys_addr_t addr, start = 0, end = MEMBLOCK_ALLOC_ACCESSIBLE;
|
||||
|
||||
memblock_dbg("%s: %llu bytes, nid=%d, exact_nid=%d %pS\n", __func__,
|
||||
(u64)size, nid, exact_nid, (void *)_RET_IP_);
|
||||
|
||||
/* Don't waste mirrored memory on HugeTLB pages. */
|
||||
flags &= ~MEMBLOCK_MIRROR;
|
||||
retry:
|
||||
/* HugeTLB pages are always aligned by their size. */
|
||||
addr = memblock_find_in_range_node(size, size, start, end, nid, flags);
|
||||
if (addr)
|
||||
goto found;
|
||||
|
||||
/* Try all nodes if allowed. */
|
||||
if (numa_valid_node(nid) && !exact_nid) {
|
||||
nid = NUMA_NO_NODE;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* Found nothing... :-( */
|
||||
return NULL;
|
||||
|
||||
found:
|
||||
/*
|
||||
* HugeTLB pages can be preserved with KHO and no preserved memory can
|
||||
* be in scratch. So retry if found address overlaps with scratch.
|
||||
*
|
||||
* Scratch areas are normally not very large, so this shouldn't take too
|
||||
* many retries.
|
||||
*/
|
||||
if (kho_scratch_overlap(addr, size)) {
|
||||
if (memblock_bottom_up())
|
||||
start = addr + size;
|
||||
else
|
||||
start = addr - size;
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (__memblock_reserve(addr, size, nid, MEMBLOCK_RSRV_KERN | MEMBLOCK_RSRV_HUGETLB))
|
||||
return NULL;
|
||||
|
||||
memblock_prep_allocation(addr, size, true);
|
||||
return phys_to_virt(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* memblock_alloc_try_nid - allocate boot memory block
|
||||
* @size: size of memory block to be allocated in bytes
|
||||
@@ -1825,6 +1891,28 @@ phys_addr_t __init_memblock memblock_reserved_size(void)
|
||||
return memblock.reserved.total_size;
|
||||
}
|
||||
|
||||
phys_addr_t __init_memblock memblock_reserved_hugetlb_size(phys_addr_t limit, int nid)
|
||||
{
|
||||
struct memblock_region *r;
|
||||
phys_addr_t total = 0;
|
||||
|
||||
for_each_reserved_mem_region(r) {
|
||||
phys_addr_t size = r->size;
|
||||
|
||||
if (r->base > limit)
|
||||
break;
|
||||
|
||||
if (r->base + r->size > limit)
|
||||
size = limit - r->base;
|
||||
|
||||
if (nid == memblock_get_region_node(r) || !numa_valid_node(nid))
|
||||
if (r->flags & MEMBLOCK_RSRV_HUGETLB)
|
||||
total += size;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
phys_addr_t __init_memblock memblock_reserved_kern_size(phys_addr_t limit, int nid)
|
||||
{
|
||||
struct memblock_region *r;
|
||||
@@ -2511,16 +2599,6 @@ __init void memblock_clear_kho_scratch_only(void)
|
||||
{
|
||||
kho_scratch_only = false;
|
||||
}
|
||||
|
||||
bool __init_memblock memblock_is_kho_scratch_memory(phys_addr_t addr)
|
||||
{
|
||||
int i = memblock_search(&memblock.memory, addr);
|
||||
|
||||
if (i == -1)
|
||||
return false;
|
||||
|
||||
return memblock_is_kho_scratch(&memblock.memory.regions[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KEXEC_HANDOVER
|
||||
|
||||
+21
-24
@@ -674,15 +674,17 @@ static inline void fixup_hashdist(void)
|
||||
static inline void fixup_hashdist(void) {}
|
||||
#endif /* CONFIG_NUMA */
|
||||
|
||||
#ifdef CONFIG_ZONE_DEVICE
|
||||
#if defined(CONFIG_ZONE_DEVICE) || defined(CONFIG_DEFERRED_STRUCT_PAGE_INIT)
|
||||
static __meminit void pageblock_migratetype_init_range(unsigned long pfn,
|
||||
unsigned long nr_pages, int migratetype)
|
||||
unsigned long nr_pages, int migratetype, bool atomic)
|
||||
{
|
||||
const unsigned long end = pfn + nr_pages;
|
||||
|
||||
for (pfn = pageblock_align(pfn); pfn < end; pfn += pageblock_nr_pages) {
|
||||
init_pageblock_migratetype(pfn_to_page(pfn), migratetype, false);
|
||||
if (IS_ALIGNED(pfn, PAGES_PER_SECTION))
|
||||
enum migratetype mt = kho_scratch_migratetype(pfn, migratetype);
|
||||
|
||||
init_pageblock_migratetype(pfn_to_page(pfn), mt, false);
|
||||
if (!atomic && IS_ALIGNED(pfn, PAGES_PER_SECTION))
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
@@ -932,8 +934,9 @@ void __meminit memmap_init_range(unsigned long size, int nid, unsigned long zone
|
||||
* over the place during system boot.
|
||||
*/
|
||||
if (pageblock_aligned(pfn)) {
|
||||
init_pageblock_migratetype(page, migratetype,
|
||||
isolate_pageblock);
|
||||
enum migratetype mt = kho_scratch_migratetype(pfn, migratetype);
|
||||
|
||||
init_pageblock_migratetype(page, mt, isolate_pageblock);
|
||||
cond_resched();
|
||||
}
|
||||
pfn++;
|
||||
@@ -943,8 +946,7 @@ void __meminit memmap_init_range(unsigned long size, int nid, unsigned long zone
|
||||
static void __init memmap_init_zone_range(struct zone *zone,
|
||||
unsigned long start_pfn,
|
||||
unsigned long end_pfn,
|
||||
unsigned long *hole_pfn,
|
||||
enum migratetype mt)
|
||||
unsigned long *hole_pfn)
|
||||
{
|
||||
unsigned long zone_start_pfn = zone->zone_start_pfn;
|
||||
unsigned long zone_end_pfn = zone_start_pfn + zone->spanned_pages;
|
||||
@@ -957,7 +959,8 @@ static void __init memmap_init_zone_range(struct zone *zone,
|
||||
return;
|
||||
|
||||
memmap_init_range(end_pfn - start_pfn, nid, zone_id, start_pfn,
|
||||
zone_end_pfn, MEMINIT_EARLY, NULL, mt, false);
|
||||
zone_end_pfn, MEMINIT_EARLY, NULL, MIGRATE_MOVABLE,
|
||||
false);
|
||||
|
||||
if (*hole_pfn < start_pfn)
|
||||
init_unavailable_range(*hole_pfn, start_pfn, zone_id, nid);
|
||||
@@ -973,8 +976,6 @@ static void __init memmap_init(void)
|
||||
|
||||
for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid) {
|
||||
struct pglist_data *node = NODE_DATA(nid);
|
||||
enum migratetype mt =
|
||||
kho_scratch_migratetype(start_pfn, MIGRATE_MOVABLE);
|
||||
|
||||
for (j = 0; j < MAX_NR_ZONES; j++) {
|
||||
struct zone *zone = node->node_zones + j;
|
||||
@@ -983,7 +984,7 @@ static void __init memmap_init(void)
|
||||
continue;
|
||||
|
||||
memmap_init_zone_range(zone, start_pfn, end_pfn,
|
||||
&hole_pfn, mt);
|
||||
&hole_pfn);
|
||||
zone_id = j;
|
||||
}
|
||||
}
|
||||
@@ -1142,7 +1143,7 @@ void __ref memmap_init_zone_device(struct zone *zone,
|
||||
compound_nr_pages(pfn, altmap, pgmap));
|
||||
}
|
||||
|
||||
pageblock_migratetype_init_range(start_pfn, nr_pages, MIGRATE_MOVABLE);
|
||||
pageblock_migratetype_init_range(start_pfn, nr_pages, MIGRATE_MOVABLE, false);
|
||||
|
||||
pr_debug("%s initialised %lu pages in %ums\n", __func__,
|
||||
nr_pages, jiffies_to_msecs(jiffies - start));
|
||||
@@ -1973,7 +1974,7 @@ unsigned long __init node_map_pfn_alignment(void)
|
||||
|
||||
#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
|
||||
static void __init deferred_free_pages(unsigned long pfn,
|
||||
unsigned long nr_pages, enum migratetype mt)
|
||||
unsigned long nr_pages)
|
||||
{
|
||||
struct page *page;
|
||||
unsigned long i;
|
||||
@@ -1981,12 +1982,12 @@ static void __init deferred_free_pages(unsigned long pfn,
|
||||
if (!nr_pages)
|
||||
return;
|
||||
|
||||
pageblock_migratetype_init_range(pfn, nr_pages, MIGRATE_MOVABLE, true);
|
||||
|
||||
page = pfn_to_page(pfn);
|
||||
|
||||
/* Free a large naturally-aligned chunk if possible */
|
||||
if (nr_pages == MAX_ORDER_NR_PAGES && IS_MAX_ORDER_ALIGNED(pfn)) {
|
||||
for (i = 0; i < nr_pages; i += pageblock_nr_pages)
|
||||
init_pageblock_migratetype(page + i, mt, false);
|
||||
__free_pages_core(page, MAX_PAGE_ORDER, MEMINIT_EARLY);
|
||||
return;
|
||||
}
|
||||
@@ -1994,11 +1995,8 @@ static void __init deferred_free_pages(unsigned long pfn,
|
||||
/* Accept chunks smaller than MAX_PAGE_ORDER upfront */
|
||||
accept_memory(PFN_PHYS(pfn), nr_pages * PAGE_SIZE);
|
||||
|
||||
for (i = 0; i < nr_pages; i++, page++, pfn++) {
|
||||
if (pageblock_aligned(pfn))
|
||||
init_pageblock_migratetype(page, mt, false);
|
||||
__free_pages_core(page, 0, MEMINIT_EARLY);
|
||||
}
|
||||
for (i = 0; i < nr_pages; i++)
|
||||
__free_pages_core(page + i, 0, MEMINIT_EARLY);
|
||||
}
|
||||
|
||||
/* Completion tracking for deferred_init_memmap() threads */
|
||||
@@ -2054,8 +2052,6 @@ deferred_init_memmap_chunk(unsigned long start_pfn, unsigned long end_pfn,
|
||||
for_each_free_mem_range(i, nid, 0, &start, &end, NULL) {
|
||||
unsigned long spfn = PFN_UP(start);
|
||||
unsigned long epfn = PFN_DOWN(end);
|
||||
enum migratetype mt =
|
||||
kho_scratch_migratetype(spfn, MIGRATE_MOVABLE);
|
||||
|
||||
if (spfn >= end_pfn)
|
||||
break;
|
||||
@@ -2068,7 +2064,7 @@ deferred_init_memmap_chunk(unsigned long start_pfn, unsigned long end_pfn,
|
||||
unsigned long chunk_end = min(mo_pfn, epfn);
|
||||
|
||||
nr_pages += deferred_init_pages(zone, spfn, chunk_end);
|
||||
deferred_free_pages(spfn, chunk_end - spfn, mt);
|
||||
deferred_free_pages(spfn, chunk_end - spfn);
|
||||
|
||||
spfn = chunk_end;
|
||||
|
||||
@@ -2687,6 +2683,7 @@ void __init __weak mem_init(void)
|
||||
|
||||
void __init mm_core_init_early(void)
|
||||
{
|
||||
kho_memory_init_early();
|
||||
hugetlb_cma_reserve();
|
||||
hugetlb_bootmem_alloc();
|
||||
|
||||
|
||||
@@ -66,4 +66,9 @@ static inline void init_deferred_page(unsigned long pfn, int nid)
|
||||
|
||||
#define __SetPageReserved(p) ((void)(p))
|
||||
|
||||
static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user