// SPDX-License-Identifier: GPL-2.0
/*
* linux/arch/parisc/mm/init.c
*
* Copyright (C) 1995 Linus Torvalds
* Copyright 1999 SuSE GmbH
* changed by Philipp Rumpf
* Copyright 1999 Philipp Rumpf (prumpf@tux.org)
* Copyright 2004 Randolph Chung (tausq@debian.org)
* Copyright 2006-2007 Helge Deller (deller@gmx.de)
*
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/memblock.h>
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/initrd.h>
#include <linux/swap.h>
#include <linux/unistd.h>
#include <linux/nodemask.h> /* for node_online_map */
#include <linux/pagemap.h> /* for release_pages */
#include <linux/compat.h>
#include <linux/execmem.h>
#include <asm/pgalloc.h>
#include <asm/tlb.h>
#include <asm/pdc_chassis.h>
#include <asm/mmzone.h>
#include <asm/sections.h>
#include <asm/msgbuf.h>
#include <asm/sparsemem.h>
#include <asm/asm-offsets.h>
#include <asm/shmbuf.h>
extern int data_start;
extern void parisc_kernel_start(void); /* Kernel entry point in head.S */
#if CONFIG_PGTABLE_LEVELS == 3
pmd_t pmd0[PTRS_PER_PMD] __section(".data..vm0.pmd") __attribute__ ((aligned(PAGE_SIZE)));
#endif
pgd_t swapper_pg_dir[PTRS_PER_PGD] __section(".data..vm0.pgd") __attribute__ ((aligned(PAGE_SIZE)));
pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __section(".data..vm0.pte") __attribute__ ((aligned(PAGE_SIZE)));
static struct resource data_resource = {
.name = "Kernel data",
.flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM,
};
static struct resource code_resource = {
.name = "Kernel code",
.flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM,
};
static struct resource pdcdata_resource = {
.name = "PDC data (Page Zero)",
.start = 0,
.end = 0x9ff,
.flags = IORESOURCE_BUSY | IORESOURCE_MEM,
};
static struct resource sysram_resources[MAX_PHYSMEM_RANGES] __ro_after_init;
/* The following array is initialized from the firmware specific
* information retrieved in kernel/inventory.c.
*/
physmem_range_t pmem_ranges[MAX_PHYSMEM_RANGES] __initdata;
int npmem_ranges __initdata;
#ifdef CONFIG_64BIT
#define MAX_MEM (1UL << MAX_PHYSMEM_BITS)
#else /* !CONFIG_64BIT */
#define MAX_MEM (3584U*1024U*1024U)
#endif /* !CONFIG_64BIT */
static unsigned long mem_limit __read_mostly = MAX_MEM;
static void __init mem_limit_func(void)
{
char *cp, *end;
unsigned long limit;
/* We need this before __setup() functions are called */
limit = MAX_MEM;
for (cp = boot_command_line; *cp; ) {
if (memcmp(cp, "mem=", 4) == 0) {
cp += 4;
limit = memparse(cp, &end);
if (end != cp)
break;
cp = end;
} else {
while (*cp != ' ' && *cp)
++cp;
while (*cp == ' ')
++cp;
}
}
if (limit < mem_limit)
mem_limit = limit;
}
#define MAX_GAP (0x40000000UL >> PAGE_SHIFT)
static void __init setup_bootmem(void)
{
unsigned long mem_max;
#ifndef CONFIG_SPARSEMEM
physmem_range_t pmem_holes[MAX_PHYSMEM_RANGES - 1];
int npmem_holes;
#endif
int i, sysram_resource_count;
disable_sr_hashing(); /* Turn off space register hashing */
/*
* Sort the ranges. Since the number of ranges is typically
* small, and performance is not an issue here, just do
* a simple insertion sort.
*/
for (i = 1; i < npmem_ranges; i++) {
int j;
for (j = i; j > 0; j--) {
if (pmem_ranges[j-1].start_pfn <
pmem_ranges[j].start_pfn) {
break;
}
swap(pmem_ranges[j-1], pmem_ranges[j]);
}
}
#ifndef CONFIG_SPARSEMEM
/*
* Throw out ranges that are too far apart (controlled by
* MAX_GAP).
*/
for (i = 1; i < npmem_ranges; i++) {
if (pmem_ranges[i].start_pfn -
(pmem_ranges[i-1].start_pfn +
pmem_ranges[i-1].pages) > MAX_GAP) {
npmem_ranges = i;
printk("Large gap in memory detected (%ld pages). "
"Consider turning on CONFIG_SPARSEMEM\n",
pmem_ranges[i].start_pfn -
(pmem_ranges[i-1].start_pfn +
pmem_ranges[i-1].pages));
break;
}
}
#endif
/* Print the memory ranges */
pr_info("Memory Ranges:\n");
for (i = 0; i < npmem_ranges; i++) {
struct resource *res = &sysram_resources[i];
unsigned long start;
unsigned long size;
size = (pmem_ranges[i].pages << PAGE_SHIFT);
start = (pmem_ranges[i].start_pfn << PAGE_SHIFT);
pr_info("%2d) Start 0x%016lx End 0x%016lx Size %6ld MB\n",
i, start, start + (size - 1), size >> 20);
/* request memory resource */
res->name = "System RAM";
res->start = start;
res->end = start + size - 1;
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
request_resource(&iomem_resource, res);
}
sysram_resource_count = npmem_ranges;
/*
* For 32 bit kernels we limit the amount of memory we can
* support, in order to preserve enough kernel address space
* for other purposes. For 64 bit kernels we don't normally
* limit the memory, but this mechanism can be used to
* artificially limit the amount of memory (and it is written
* to work with multiple memory ranges).
*/
mem_limit_func(); /* check for "mem=" argument */
mem_max = 0;
for (i = 0; i < npmem_ranges; i++) {
unsigned long rsize;
rsize = pmem_ranges