2018-07-23 05:58:19

by Mike Rapoport

[permalink] [raw]
Subject: [PATCH 0/4] ia64: switch to NO_BOOTMEM

Hi,

These patches convert ia64 to use NO_BOOTMEM.

The first two patches are cleanups, the third patches reduces usage of
'struct bootmem_data' for easier transition and the forth patch actually
replaces bootmem with memblock + nobootmem.

I've tested the sim_defconfig with the ski simulator and build tested other
defconfigs.

Mike Rapoport (4):
ia64: contig/paging_init: reduce code duplication
ia64: remove unused num_dma_physpages member from 'struct early_node_data'
ia64: use mem_data to detect nodes' minimal and maximal PFNs
ia64: switch to NO_BOOTMEM

arch/ia64/Kconfig | 1 +
arch/ia64/kernel/setup.c | 11 +++-
arch/ia64/mm/contig.c | 75 +++-----------------------
arch/ia64/mm/discontig.c | 134 ++++++-----------------------------------------
4 files changed, 33 insertions(+), 188 deletions(-)

--
2.7.4



2018-07-23 05:58:23

by Mike Rapoport

[permalink] [raw]
Subject: [PATCH 4/4] ia64: switch to NO_BOOTMEM

Since ia64 already uses memblock to register available physical memory it
is only required to move the calls to register_active_ranges() that wrap
memblock_add_node() earlier and replace bootmem memory reservations with
memblock_reserve(). Of course, all the code that find the place to put the
bootmem bitmap is removed.

Signed-off-by: Mike Rapoport <[email protected]>
---
arch/ia64/Kconfig | 1 +
arch/ia64/kernel/setup.c | 11 ++++++-
arch/ia64/mm/contig.c | 71 ++++------------------------------------------
arch/ia64/mm/discontig.c | 74 ++++--------------------------------------------
4 files changed, 22 insertions(+), 135 deletions(-)

diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index ff86142..107b138 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -31,6 +31,7 @@ config IA64
select HAVE_ARCH_TRACEHOOK
select HAVE_MEMBLOCK
select HAVE_MEMBLOCK_NODE_MAP
+ select NO_BOOTMEM
select HAVE_VIRT_CPU_ACCOUNTING
select ARCH_HAS_DMA_MARK_CLEAN
select ARCH_HAS_SG_CHAIN
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index ad43cbf..b042d0c 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/cpu.h>
#include <linux/kernel.h>
+#include <linux/memblock.h>
#include <linux/reboot.h>
#include <linux/sched/mm.h>
#include <linux/sched/clock.h>
@@ -383,8 +384,16 @@ reserve_memory (void)

sort_regions(rsvd_region, num_rsvd_regions);
num_rsvd_regions = merge_regions(rsvd_region, num_rsvd_regions);
-}

+ /* reserve all regions except the end of memory marker with meblock */
+ for (n = 0; n < num_rsvd_regions - 1; n++) {
+ struct rsvd_region *region = &rsvd_region[n];
+ phys_addr_t addr = __pa(region->start);
+ phys_addr_t size = region->end - region->start;
+
+ memblock_reserve(addr, size);
+ }
+}

/**
* find_initrd - get initrd parameters from the boot parameter structure
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index 1835144..e2e40bb 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -34,53 +34,6 @@ static unsigned long max_gap;
/* physical address where the bootmem map is located */
unsigned long bootmap_start;

-/**
- * find_bootmap_location - callback to find a memory area for the bootmap
- * @start: start of region
- * @end: end of region
- * @arg: unused callback data
- *
- * Find a place to put the bootmap and return its starting address in
- * bootmap_start. This address must be page-aligned.
- */
-static int __init
-find_bootmap_location (u64 start, u64 end, void *arg)
-{
- u64 needed = *(unsigned long *)arg;
- u64 range_start, range_end, free_start;
- int i;
-
-#if IGNORE_PFN0
- if (start == PAGE_OFFSET) {
- start += PAGE_SIZE;
- if (start >= end)
- return 0;
- }
-#endif
-
- free_start = PAGE_OFFSET;
-
- for (i = 0; i < num_rsvd_regions; i++) {
- range_start = max(start, free_start);
- range_end = min(end, rsvd_region[i].start & PAGE_MASK);
-
- free_start = PAGE_ALIGN(rsvd_region[i].end);
-
- if (range_end <= range_start)
- continue; /* skip over empty range */
-
- if (range_end - range_start >= needed) {
- bootmap_start = __pa(range_start);
- return -1; /* done */
- }
-
- /* nothing more available in this segment */
- if (range_end == end)
- return 0;
- }
- return 0;
-}
-
#ifdef CONFIG_SMP
static void *cpu_data;
/**
@@ -196,8 +149,6 @@ setup_per_cpu_areas(void)
void __init
find_memory (void)
{
- unsigned long bootmap_size;
-
reserve_memory();

/* first find highest page frame number */
@@ -205,21 +156,12 @@ find_memory (void)
max_low_pfn = 0;
efi_memmap_walk(find_max_min_low_pfn, NULL);
max_pfn = max_low_pfn;
- /* how many bytes to cover all the pages */
- bootmap_size = bootmem_bootmap_pages(max_pfn) << PAGE_SHIFT;

- /* look for a location to hold the bootmap */
- bootmap_start = ~0UL;
- efi_memmap_walk(find_bootmap_location, &bootmap_size);
- if (bootmap_start == ~0UL)
- panic("Cannot find %ld bytes for bootmap\n", bootmap_size);
-
- bootmap_size = init_bootmem_node(NODE_DATA(0),
- (bootmap_start >> PAGE_SHIFT), 0, max_pfn);
-
- /* Free all available memory, then mark bootmem-map as being in use. */
- efi_memmap_walk(filter_rsvd_memory, free_bootmem);
- reserve_bootmem(bootmap_start, bootmap_size, BOOTMEM_DEFAULT);
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+ efi_memmap_walk(filter_memory, register_active_ranges);
+#else
+ memblock_add_node(0, PFN_PHYS(max_low_pfn), 0);
+#endif

find_initrd();

@@ -244,7 +186,6 @@ paging_init (void)
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;

#ifdef CONFIG_VIRTUAL_MEM_MAP
- efi_memmap_walk(filter_memory, register_active_ranges);
efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
if (max_gap < LARGE_GAP) {
vmem_map = (struct page *) 0;
@@ -268,8 +209,6 @@ paging_init (void)

printk("Virtual mem_map starts at 0x%p\n", mem_map);
}
-#else /* !CONFIG_VIRTUAL_MEM_MAP */
- memblock_add_node(0, PFN_PHYS(max_low_pfn), 0);
#endif /* !CONFIG_VIRTUAL_MEM_MAP */
free_area_init_nodes(max_zone_pfns);
zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 8e99d8e..1928d57 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -20,6 +20,7 @@
#include <linux/nmi.h>
#include <linux/swap.h>
#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/acpi.h>
#include <linux/efi.h>
#include <linux/nodemask.h>
@@ -264,7 +265,6 @@ static void __init fill_pernode(int node, unsigned long pernode,
{
void *cpu_data;
int cpus = early_nr_cpus_node(node);
- struct bootmem_data *bdp = &bootmem_node_data[node];

mem_data[node].pernode_addr = pernode;
mem_data[node].pernode_size = pernodesize;
@@ -279,8 +279,6 @@ static void __init fill_pernode(int node, unsigned long pernode,

mem_data[node].node_data = __va(pernode);
pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
-
- pgdat_list[node]->bdata = bdp;
pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));

cpu_data = per_cpu_node_setup(cpu_data, node);
@@ -320,14 +318,11 @@ static int __init find_pernode_space(unsigned long start, unsigned long len,
int node)
{
unsigned long spfn, epfn;
- unsigned long pernodesize = 0, pernode, pages, mapsize;
+ unsigned long pernodesize = 0, pernode;

spfn = start >> PAGE_SHIFT;
epfn = (start + len) >> PAGE_SHIFT;

- pages = mem_data[node].max_pfn - mem_data[node].min_pfn;
- mapsize = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
-
/*
* Make sure this memory falls within this node's usable memory
* since we may have thrown some away in build_maps().
@@ -347,32 +342,13 @@ static int __init find_pernode_space(unsigned long start, unsigned long len,
pernode = NODEDATA_ALIGN(start, node);

/* Is this range big enough for what we want to store here? */
- if (start + len > (pernode + pernodesize + mapsize))
+ if (start + len > (pernode + pernodesize))
fill_pernode(node, pernode, pernodesize);

return 0;
}

/**
- * free_node_bootmem - free bootmem allocator memory for use
- * @start: physical start of range
- * @len: length of range
- * @node: node where this range resides
- *
- * Simply calls the bootmem allocator to free the specified ranged from
- * the given pg_data_t's bdata struct. After this function has been called
- * for all the entries in the EFI memory map, the bootmem allocator will
- * be ready to service allocation requests.
- */
-static int __init free_node_bootmem(unsigned long start, unsigned long len,
- int node)
-{
- free_bootmem_node(pgdat_list[node], start, len);
-
- return 0;
-}
-
-/**
* reserve_pernode_space - reserve memory for per-node space
*
* Reserve the space used by the bootmem maps & per-node space in the boot
@@ -381,28 +357,17 @@ static int __init free_node_bootmem(unsigned long start, unsigned long len,
*/
static void __init reserve_pernode_space(void)
{
- unsigned long base, size, pages;
- struct bootmem_data *bdp;
+ unsigned long base, size;
int node;

for_each_online_node(node) {
- pg_data_t *pdp = pgdat_list[node];
-
if (node_isset(node, memory_less_mask))
continue;

- bdp = pdp->bdata;
-
- /* First the bootmem_map itself */
- pages = mem_data[node].max_pfn - mem_data[node].min_pfn;
- size = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
- base = __pa(bdp->node_bootmem_map);
- reserve_bootmem_node(pdp, base, size, BOOTMEM_DEFAULT);
-
/* Now the per-node space */
size = mem_data[node].pernode_size;
base = __pa(mem_data[node].pernode_addr);
- reserve_bootmem_node(pdp, base, size, BOOTMEM_DEFAULT);
+ memblock_reserve(base, size);
}
}

@@ -522,6 +487,7 @@ void __init find_memory(void)
int node;

reserve_memory();
+ efi_memmap_walk(filter_memory, register_active_ranges);

if (num_online_nodes() == 0) {
printk(KERN_ERR "node info missing!\n");
@@ -541,34 +507,6 @@ void __init find_memory(void)
if (mem_data[node].min_pfn)
node_clear(node, memory_less_mask);

- efi_memmap_walk(filter_memory, register_active_ranges);
-
- /*
- * Initialize the boot memory maps in reverse order since that's
- * what the bootmem allocator expects
- */
- for (node = MAX_NUMNODES - 1; node >= 0; node--) {
- unsigned long pernode, pernodesize, map;
- struct bootmem_data *bdp;
-
- if (!node_online(node))
- continue;
- else if (node_isset(node, memory_less_mask))
- continue;
-
- bdp = &bootmem_node_data[node];
- pernode = mem_data[node].pernode_addr;
- pernodesize = mem_data[node].pernode_size;
- map = pernode + pernodesize;
-
- init_bootmem_node(pgdat_list[node],
- map>>PAGE_SHIFT,
- mem_data[node].min_pfn,
- mem_data[node].max_pfn);
- }
-
- efi_memmap_walk(filter_rsvd_memory, free_node_bootmem);
-
reserve_pernode_space();
memory_less_nodes();
initialize_pernode_data();
--
2.7.4


2018-07-23 05:58:34

by Mike Rapoport

[permalink] [raw]
Subject: [PATCH 2/4] ia64: remove unused num_dma_physpages member from 'struct early_node_data'

Since commit 05e0caad3b7b ("[PATCH] Have ia64 use add_active_range() and
free_area_init_nodes") the num_dma_physpages member of 'struct
early_node_data' is calculated but never used. Remove it.

Signed-off-by: Mike Rapoport <[email protected]>
---
arch/ia64/mm/discontig.c | 8 --------
1 file changed, 8 deletions(-)

diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 7d9bd20..6148ea8 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -38,9 +38,6 @@ struct early_node_data {
struct ia64_node_data *node_data;
unsigned long pernode_addr;
unsigned long pernode_size;
-#ifdef CONFIG_ZONE_DMA32
- unsigned long num_dma_physpages;
-#endif
unsigned long min_pfn;
unsigned long max_pfn;
};
@@ -669,11 +666,6 @@ static __init int count_node_pages(unsigned long start, unsigned long len, int n
{
unsigned long end = start + len;

-#ifdef CONFIG_ZONE_DMA32
- if (start <= __pa(MAX_DMA_ADDRESS))
- mem_data[node].num_dma_physpages +=
- (min(end, __pa(MAX_DMA_ADDRESS)) - start) >>PAGE_SHIFT;
-#endif
start = GRANULEROUNDDOWN(start);
end = GRANULEROUNDUP(end);
mem_data[node].max_pfn = max(mem_data[node].max_pfn,
--
2.7.4


2018-07-23 05:59:06

by Mike Rapoport

[permalink] [raw]
Subject: [PATCH 3/4] ia64: use mem_data to detect nodes' minimal and maximal PFNs

When EFI memory map is traversed to determine the extents of each node, the
minimal and maximal PFNs are stored in the bootmem_data structures. The
same information ls later stored in the mem_data array of 'struct
early_node_data'.

Switch to using mem_data from the very beginning.

Signed-off-by: Mike Rapoport <[email protected]>
---
arch/ia64/mm/discontig.c | 60 +++++++++++-------------------------------------
1 file changed, 14 insertions(+), 46 deletions(-)

diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 6148ea8..8e99d8e 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -57,33 +57,31 @@ pg_data_t *pgdat_list[MAX_NUMNODES];
(((node)*PERCPU_PAGE_SIZE) & (MAX_NODE_ALIGN_OFFSET - 1)))

/**
- * build_node_maps - callback to setup bootmem structs for each node
+ * build_node_maps - callback to setup mem_data structs for each node
* @start: physical start of range
* @len: length of range
* @node: node where this range resides
*
- * We allocate a struct bootmem_data for each piece of memory that we wish to
+ * Detect extents of each piece of memory that we wish to
* treat as a virtually contiguous block (i.e. each node). Each such block
* must start on an %IA64_GRANULE_SIZE boundary, so we round the address down
* if necessary. Any non-existent pages will simply be part of the virtual
- * memmap. We also update min_low_pfn and max_low_pfn here as we receive
- * memory ranges from the caller.
+ * memmap.
*/
static int __init build_node_maps(unsigned long start, unsigned long len,
int node)
{
unsigned long spfn, epfn, end = start + len;
- struct bootmem_data *bdp = &bootmem_node_data[node];

epfn = GRANULEROUNDUP(end) >> PAGE_SHIFT;
spfn = GRANULEROUNDDOWN(start) >> PAGE_SHIFT;

- if (!bdp->node_low_pfn) {
- bdp->node_min_pfn = spfn;
- bdp->node_low_pfn = epfn;
+ if (!mem_data[node].min_pfn) {
+ mem_data[node].min_pfn = spfn;
+ mem_data[node].max_pfn = epfn;
} else {
- bdp->node_min_pfn = min(spfn, bdp->node_min_pfn);
- bdp->node_low_pfn = max(epfn, bdp->node_low_pfn);
+ mem_data[node].min_pfn = min(spfn, mem_data[node].min_pfn);
+ mem_data[node].max_pfn = max(epfn, mem_data[node].max_pfn);
}

return 0;
@@ -323,19 +321,18 @@ static int __init find_pernode_space(unsigned long start, unsigned long len,
{
unsigned long spfn, epfn;
unsigned long pernodesize = 0, pernode, pages, mapsize;
- struct bootmem_data *bdp = &bootmem_node_data[node];

spfn = start >> PAGE_SHIFT;
epfn = (start + len) >> PAGE_SHIFT;

- pages = bdp->node_low_pfn - bdp->node_min_pfn;
+ pages = mem_data[node].max_pfn - mem_data[node].min_pfn;
mapsize = bootmem_bootmap_pages(pages) << PAGE_SHIFT;

/*
* Make sure this memory falls within this node's usable memory
* since we may have thrown some away in build_maps().
*/
- if (spfn < bdp->node_min_pfn || epfn > bdp->node_low_pfn)
+ if (spfn < mem_data[node].min_pfn || epfn > mem_data[node].max_pfn)
return 0;

/* Don't setup this node's local space twice... */
@@ -397,7 +394,7 @@ static void __init reserve_pernode_space(void)
bdp = pdp->bdata;

/* First the bootmem_map itself */
- pages = bdp->node_low_pfn - bdp->node_min_pfn;
+ pages = mem_data[node].max_pfn - mem_data[node].min_pfn;
size = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
base = __pa(bdp->node_bootmem_map);
reserve_bootmem_node(pdp, base, size, BOOTMEM_DEFAULT);
@@ -541,10 +538,8 @@ void __init find_memory(void)
efi_memmap_walk(find_max_min_low_pfn, NULL);

for_each_online_node(node)
- if (bootmem_node_data[node].node_low_pfn) {
+ if (mem_data[node].min_pfn)
node_clear(node, memory_less_mask);
- mem_data[node].min_pfn = ~0UL;
- }

efi_memmap_walk(filter_memory, register_active_ranges);

@@ -568,8 +563,8 @@ void __init find_memory(void)

init_bootmem_node(pgdat_list[node],
map>>PAGE_SHIFT,
- bdp->node_min_pfn,
- bdp->node_low_pfn);
+ mem_data[node].min_pfn,
+ mem_data[node].max_pfn);
}

efi_memmap_walk(filter_rsvd_memory, free_node_bootmem);
@@ -652,31 +647,6 @@ void call_pernode_memory(unsigned long start, unsigned long len, void *arg)
}

/**
- * count_node_pages - callback to build per-node memory info structures
- * @start: physical start of range
- * @len: length of range
- * @node: node where this range resides
- *
- * Each node has it's own number of physical pages, DMAable pages, start, and
- * end page frame number. This routine will be called by call_pernode_memory()
- * for each piece of usable memory and will setup these values for each node.
- * Very similar to build_maps().
- */
-static __init int count_node_pages(unsigned long start, unsigned long len, int node)
-{
- unsigned long end = start + len;
-
- start = GRANULEROUNDDOWN(start);
- end = GRANULEROUNDUP(end);
- mem_data[node].max_pfn = max(mem_data[node].max_pfn,
- end >> PAGE_SHIFT);
- mem_data[node].min_pfn = min(mem_data[node].min_pfn,
- start >> PAGE_SHIFT);
-
- return 0;
-}
-
-/**
* paging_init - setup page tables
*
* paging_init() sets up the page tables for each node of the system and frees
@@ -692,8 +662,6 @@ void __init paging_init(void)

max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;

- efi_memmap_walk(filter_rsvd_memory, count_node_pages);
-
sparse_memory_present_with_active_regions(MAX_NUMNODES);
sparse_init();

--
2.7.4


2018-07-23 05:59:26

by Mike Rapoport

[permalink] [raw]
Subject: [PATCH 1/4] ia64: contig/paging_init: reduce code duplication

The FLATMEM version of paging_init has calls to free_area_init_nodes() in
the end of every branch of 'if' and 'ifdef' statements.

Let's call this function outside the 'ifdef' and 'if' statements instead.

Signed-off-by: Mike Rapoport <[email protected]>
---
arch/ia64/mm/contig.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index 7d64b30..1835144 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -248,7 +248,6 @@ paging_init (void)
efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
if (max_gap < LARGE_GAP) {
vmem_map = (struct page *) 0;
- free_area_init_nodes(max_zone_pfns);
} else {
unsigned long map_size;

@@ -266,13 +265,12 @@ paging_init (void)
*/
NODE_DATA(0)->node_mem_map = vmem_map +
find_min_pfn_with_active_regions();
- free_area_init_nodes(max_zone_pfns);

printk("Virtual mem_map starts at 0x%p\n", mem_map);
}
#else /* !CONFIG_VIRTUAL_MEM_MAP */
memblock_add_node(0, PFN_PHYS(max_low_pfn), 0);
- free_area_init_nodes(max_zone_pfns);
#endif /* !CONFIG_VIRTUAL_MEM_MAP */
+ free_area_init_nodes(max_zone_pfns);
zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
}
--
2.7.4


2018-07-23 21:02:19

by Luck, Tony

[permalink] [raw]
Subject: Re: [PATCH 0/4] ia64: switch to NO_BOOTMEM

On Mon, Jul 23, 2018 at 08:56:54AM +0300, Mike Rapoport wrote:
> Hi,
>
> These patches convert ia64 to use NO_BOOTMEM.
>
> The first two patches are cleanups, the third patches reduces usage of
> 'struct bootmem_data' for easier transition and the forth patch actually
> replaces bootmem with memblock + nobootmem.
>
> I've tested the sim_defconfig with the ski simulator and build tested other
> defconfigs.

Boots OK on my real ia64 system.

Unless somebody else sees an issue I'll push to Linus nest merge window.

-Tony