OpenCloudOS-Kernel/arch/mips/kernel/setup.c

1042 lines
25 KiB
C
Raw Normal View History

/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1995 Linus Torvalds
* Copyright (C) 1995 Waldorf Electronics
* Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03 Ralf Baechle
* Copyright (C) 1996 Stoned Elipot
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2000, 2001, 2002, 2007 Maciej W. Rozycki
*/
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/export.h>
#include <linux/screen_info.h>
#include <linux/memblock.h>
#include <linux/initrd.h>
#include <linux/root_dev.h>
#include <linux/highmem.h>
#include <linux/console.h>
#include <linux/pfn.h>
#include <linux/debugfs.h>
#include <linux/kexec.h>
#include <linux/sizes.h>
#include <linux/device.h>
#include <linux/dma-contiguous.h>
#include <linux/decompress/generic.h>
#include <linux/of_fdt.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
[MIPS] R4000/R4400 errata workarounds This is the gereric part of R4000/R4400 errata workarounds. They include compiler and assembler support as well as some source code modifications to address the problems with some combinations of multiply/divide+shift instructions as well as the daddi and daddiu instructions. Changes included are as follows: 1. New Kconfig options to select workarounds by platforms as necessary. 2. Arch top-level Makefile to pass necessary options to the compiler; also incompatible configurations are detected (-mno-sym32 unsupported as horribly intrusive for little gain). 3. Bug detection updated and shuffled -- the multiply/divide+shift problem is lethal enough that if not worked around it makes the kernel crash in time_init() because of a division by zero; the daddiu erratum might also trigger early potentially, though I have not observed it. On the other hand the daddi detection code requires the exception subsystem to have been initialised (and is there mainly for information). 4. r4k_daddiu_bug() added so that the existence of the erratum can be queried by code at the run time as necessary; useful for generated code like TLB fault and copy/clear page handlers. 5. __udelay() updated as it uses multiplication in inline assembly. Note that -mdaddi requires modified toolchain (which has been maintained by myself and available from my site for ~4years now -- versions covered are GCC 2.95.4 - 4.1.2 and binutils from 2.13 onwards). The -mfix-r4000 and -mfix-r4400 have been standard for a while though. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2007-10-23 19:43:11 +08:00
#include <asm/bugs.h>
#include <asm/cache.h>
#include <asm/cdmm.h>
#include <asm/cpu.h>
#include <asm/debug.h>
#include <asm/dma-coherence.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/smp-ops.h>
#include <asm/prom.h>
#ifdef CONFIG_MIPS_ELF_APPENDED_DTB
const char __section(.appended_dtb) __appended_dtb[0x100000];
#endif /* CONFIG_MIPS_ELF_APPENDED_DTB */
struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_data);
#ifdef CONFIG_VT
struct screen_info screen_info;
#endif
/*
* Setup information
*
* These are initialized so they are in the .data section
*/
unsigned long mips_machtype __read_mostly = MACH_UNKNOWN;
EXPORT_SYMBOL(mips_machtype);
struct boot_mem_map boot_mem_map;
static char __initdata command_line[COMMAND_LINE_SIZE];
char __initdata arcs_cmdline[COMMAND_LINE_SIZE];
#ifdef CONFIG_CMDLINE_BOOL
static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
#endif
/*
* mips_io_port_base is the begin of the address space to which x86 style
* I/O ports are mapped.
*/
const unsigned long mips_io_port_base = -1;
EXPORT_SYMBOL(mips_io_port_base);
static struct resource code_resource = { .name = "Kernel code", };
static struct resource data_resource = { .name = "Kernel data", };
static struct resource bss_resource = { .name = "Kernel bss", };
static void *detect_magic __initdata = detect_memory_region;
#ifdef CONFIG_MIPS_AUTO_PFN_OFFSET
unsigned long ARCH_PFN_OFFSET;
EXPORT_SYMBOL(ARCH_PFN_OFFSET);
#endif
void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type)
{
int x = boot_mem_map.nr_map;
int i;
/*
* If the region reaches the top of the physical address space, adjust
* the size slightly so that (start + size) doesn't overflow
*/
if (start + size - 1 == PHYS_ADDR_MAX)
--size;
/* Sanity check */
if (start + size < start) {
pr_warn("Trying to add an invalid memory region, skipped\n");
return;
}
/*
* Try to merge with existing entry, if any.
*/
for (i = 0; i < boot_mem_map.nr_map; i++) {
struct boot_mem_map_entry *entry = boot_mem_map.map + i;
unsigned long top;
if (entry->type != type)
continue;
if (start + size < entry->addr)
continue; /* no overlap */
if (entry->addr + entry->size < start)
continue; /* no overlap */
top = max(entry->addr + entry->size, start + size);
entry->addr = min(entry->addr, start);
entry->size = top - entry->addr;
return;
}
if (boot_mem_map.nr_map == BOOT_MEM_MAP_MAX) {
pr_err("Ooops! Too many entries in the memory map!\n");
return;
}
boot_mem_map.map[x].addr = start;
boot_mem_map.map[x].size = size;
boot_mem_map.map[x].type = type;
boot_mem_map.nr_map++;
}
void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max)
{
void *dm = &detect_magic;
phys_addr_t size;
for (size = sz_min; size < sz_max; size <<= 1) {
if (!memcmp(dm, dm + size, sizeof(detect_magic)))
break;
}
pr_debug("Memory: %lluMB of RAM detected at 0x%llx (min: %lluMB, max: %lluMB)\n",
((unsigned long long) size) / SZ_1M,
(unsigned long long) start,
((unsigned long long) sz_min) / SZ_1M,
((unsigned long long) sz_max) / SZ_1M);
add_memory_region(start, size, BOOT_MEM_RAM);
}
static bool __init __maybe_unused memory_region_available(phys_addr_t start,
phys_addr_t size)
{
int i;
bool in_ram = false, free = true;
for (i = 0; i < boot_mem_map.nr_map; i++) {
phys_addr_t start_, end_;
start_ = boot_mem_map.map[i].addr;
end_ = boot_mem_map.map[i].addr + boot_mem_map.map[i].size;
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RAM:
if (start >= start_ && start + size <= end_)
in_ram = true;
break;
case BOOT_MEM_RESERVED:
if ((start >= start_ && start < end_) ||
(start < start_ && start + size >= start_))
free = false;
break;
default:
continue;
}
}
return in_ram && free;
}
static void __init print_memory_map(void)
{
int i;
const int field = 2 * sizeof(unsigned long);
for (i = 0; i < boot_mem_map.nr_map; i++) {
printk(KERN_INFO " memory: %0*Lx @ %0*Lx ",
field, (unsigned long long) boot_mem_map.map[i].size,
field, (unsigned long long) boot_mem_map.map[i].addr);
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RAM:
printk(KERN_CONT "(usable)\n");
break;
MIPS: Handle initmem in systems with kernel not in add_memory_region() mem This patch addresses a couple of related problems: 1) The kernel may reside in physical memory outside of the ranges set by plat_mem_setup(). If this is the case, init mem cannot be reused as it resides outside of the range of pages that the kernel memory allocators control. 2) initrd images might be loaded in physical memory outside of the ranges set by plat_mem_setup(). The memory likewise cannot be reused. The patch doesn't handle this specific case, but the infrastructure is useful for future patches that do. The crux of the problem is that there are memory regions that need be memory_present(), but that cannot be free_bootmem() at the time of arch_mem_init(). We create a new type of memory (BOOT_MEM_INIT_RAM) for use with add_memory_region(). Then arch_mem_init() adds the init mem with this type if the init mem is not already covered by existing ranges. When memory is being freed into the bootmem allocator, we skip the BOOT_MEM_INIT_RAM ranges so they are not clobbered, but we do signal them as memory_present(). This way when they are later freed, the necessary memory manager structures have initialized and the Sparse allocater is prevented from crashing. The Octeon specific code that handled this case is removed, because the new general purpose code handles the case. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1988/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2011-11-22 22:38:03 +08:00
case BOOT_MEM_INIT_RAM:
printk(KERN_CONT "(usable after init)\n");
break;
case BOOT_MEM_ROM_DATA:
printk(KERN_CONT "(ROM data)\n");
break;
case BOOT_MEM_RESERVED:
printk(KERN_CONT "(reserved)\n");
break;
default:
printk(KERN_CONT "type %lu\n", boot_mem_map.map[i].type);
break;
}
}
}
/*
* Manage initrd
*/
#ifdef CONFIG_BLK_DEV_INITRD
static int __init rd_start_early(char *p)
{
unsigned long start = memparse(p, &p);
#ifdef CONFIG_64BIT
/* Guess if the sign extension was forgotten by bootloader */
if (start < XKPHYS)
start = (int)start;
#endif
initrd_start = start;
initrd_end += start;
return 0;
}
early_param("rd_start", rd_start_early);
static int __init rd_size_early(char *p)
{
initrd_end += memparse(p, &p);
return 0;
}
early_param("rd_size", rd_size_early);
/* it returns the next free pfn after initrd */
static unsigned long __init init_initrd(void)
{
unsigned long end;
/*
* Board specific code or command line parser should have
* already set up initrd_start and initrd_end. In these cases
* perfom sanity checks and use them if all looks good.
*/
if (!initrd_start || initrd_end <= initrd_start)
goto disable;
if (initrd_start & ~PAGE_MASK) {
pr_err("initrd start must be page aligned\n");
goto disable;
}
if (initrd_start < PAGE_OFFSET) {
pr_err("initrd start < PAGE_OFFSET\n");
goto disable;
}
/*
* Sanitize initrd addresses. For example firmware
* can't guess if they need to pass them through
* 64-bits values if the kernel has been built in pure
* 32-bit. We need also to switch from KSEG0 to XKPHYS
* addresses now, so the code can now safely use __pa().
*/
end = __pa(initrd_end);
initrd_end = (unsigned long)__va(end);
initrd_start = (unsigned long)__va(__pa(initrd_start));
ROOT_DEV = Root_RAM0;
return PFN_UP(end);
disable:
initrd_start = 0;
initrd_end = 0;
return 0;
}
/* In some conditions (e.g. big endian bootloader with a little endian
kernel), the initrd might appear byte swapped. Try to detect this and
byte swap it if needed. */
static void __init maybe_bswap_initrd(void)
{
#if defined(CONFIG_CPU_CAVIUM_OCTEON)
u64 buf;
/* Check for CPIO signature */
if (!memcmp((void *)initrd_start, "070701", 6))
return;
/* Check for compressed initrd */
if (decompress_method((unsigned char *)initrd_start, 8, NULL))
return;
/* Try again with a byte swapped header */
buf = swab64p((u64 *)initrd_start);
if (!memcmp(&buf, "070701", 6) ||
decompress_method((unsigned char *)(&buf), 8, NULL)) {
unsigned long i;
pr_info("Byteswapped initrd detected\n");
for (i = initrd_start; i < ALIGN(initrd_end, 8); i += 8)
swab64s((u64 *)i);
}
#endif
}
static void __init finalize_initrd(void)
{
unsigned long size = initrd_end - initrd_start;
if (size == 0) {
printk(KERN_INFO "Initrd not found or empty");
goto disable;
}
if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) {
printk(KERN_ERR "Initrd extends beyond end of memory");
goto disable;
}
maybe_bswap_initrd();
memblock_reserve(__pa(initrd_start), size);
initrd_below_start_ok = 1;
pr_info("Initial ramdisk at: 0x%lx (%lu bytes)\n",
initrd_start, size);
return;
disable:
printk(KERN_CONT " - disabling initrd\n");
initrd_start = 0;
initrd_end = 0;
}
#else /* !CONFIG_BLK_DEV_INITRD */
static unsigned long __init init_initrd(void)
{
return 0;
}
#define finalize_initrd() do {} while (0)
#endif
/*
* Initialize the bootmem allocator. It also setup initrd related data
* if needed.
*/
#if defined(CONFIG_SGI_IP27) || (defined(CONFIG_CPU_LOONGSON3) && defined(CONFIG_NUMA))
static void __init bootmem_init(void)
{
init_initrd();
finalize_initrd();
}
#else /* !CONFIG_SGI_IP27 */
static void __init bootmem_init(void)
{
unsigned long reserved_end;
phys_addr_t ramstart = PHYS_ADDR_MAX;
int i;
/*
* Sanity check any INITRD first. We don't take it into account
* for bootmem setup initially, rely on the end-of-kernel-code
* as our memory range starting point. Once bootmem is inited we
* will reserve the area used for the initrd.
*/
init_initrd();
reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end));
memblock_reserve(PHYS_OFFSET,
(reserved_end << PAGE_SHIFT) - PHYS_OFFSET);
/*
* max_low_pfn is not a number of pages. The number of pages
* of the system is given by 'max_low_pfn - min_low_pfn'.
*/
min_low_pfn = ~0UL;
max_low_pfn = 0;
/*
* Find the highest page frame number we have available
* and the lowest used RAM address
*/
for (i = 0; i < boot_mem_map.nr_map; i++) {
unsigned long start, end;
if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
continue;
start = PFN_UP(boot_mem_map.map[i].addr);
end = PFN_DOWN(boot_mem_map.map[i].addr
+ boot_mem_map.map[i].size);
ramstart = min(ramstart, boot_mem_map.map[i].addr);
#ifndef CONFIG_HIGHMEM
/*
* Skip highmem here so we get an accurate max_low_pfn if low
* memory stops short of high memory.
* If the region overlaps HIGHMEM_START, end is clipped so
* max_pfn excludes the highmem portion.
*/
if (start >= PFN_DOWN(HIGHMEM_START))
continue;
if (end > PFN_DOWN(HIGHMEM_START))
end = PFN_DOWN(HIGHMEM_START);
#endif
if (end > max_low_pfn)
max_low_pfn = end;
if (start < min_low_pfn)
min_low_pfn = start;
if (end <= reserved_end)
continue;
MIPS: bootmem: Don't use memory holes for page bitmap Commit f9a7febd leads to a fact that mapstart and therefore a page bitmap for bootmem allocator immediately follows initrd_end. This doesn't always work well on Octeon, where there are holes in PFN ranges (refer to 5b3b1688 and 4MB-aligned PFN allocation). Depending on the inird location it could happen, that mapstart would be in an area not allocated by plat_mem_setup() in arch/mips/cavium-octeon/setup.c, but in the alignment hole between initrd and the next PFN area. Later on this memory will be unconditionally made available to buddy allocator at the end of free_all_bootmem_core() (mm/bootmem.c). All of this results in Linux using the memory not designated for Linux in Octeon's plat_mem_setup(), which in turn means corruption of the memory used by another OS/baremetal code on the same SoC. It doesn't look to me as a problem of Octeon platform code, but rather as an inability of f9a7febd to deal correctly with the fragmented memory-mappings. Proposed fix moves the check for initrd address to the same calculation-loop in bootmem_init() (arch/mips/kernel/setup.c), which also accounts for kernel code location. This should result in mapstart located starting from the first PFN area after kernel code AND initrd. Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com> Cc: linux-mips@linux-mips.org Cc: David Daney <david.daney@cavium.com> Cc: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> Cc: Huacai Chen <chenhc@lemote.com> Cc: Andreas Herrmann <andreas.herrmann@caviumnetworks.com> Cc: Joe Perches <joe@perches.com> Cc: Steven J. Hill <Steven.Hill@imgtec.com> Cc: Yusuf Khan <yusuf.khan@nokia.com> Cc: Michael Kreuzer <michael.kreuzer@nokia.com> Cc: Aaro Koskinen <aaro.koskinen@iki.fi> Patchwork: https://patchwork.linux-mips.org/patch/10594/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2015-07-02 23:16:01 +08:00
#ifdef CONFIG_BLK_DEV_INITRD
/* Skip zones before initrd and initrd itself */
MIPS: bootmem: Don't use memory holes for page bitmap Commit f9a7febd leads to a fact that mapstart and therefore a page bitmap for bootmem allocator immediately follows initrd_end. This doesn't always work well on Octeon, where there are holes in PFN ranges (refer to 5b3b1688 and 4MB-aligned PFN allocation). Depending on the inird location it could happen, that mapstart would be in an area not allocated by plat_mem_setup() in arch/mips/cavium-octeon/setup.c, but in the alignment hole between initrd and the next PFN area. Later on this memory will be unconditionally made available to buddy allocator at the end of free_all_bootmem_core() (mm/bootmem.c). All of this results in Linux using the memory not designated for Linux in Octeon's plat_mem_setup(), which in turn means corruption of the memory used by another OS/baremetal code on the same SoC. It doesn't look to me as a problem of Octeon platform code, but rather as an inability of f9a7febd to deal correctly with the fragmented memory-mappings. Proposed fix moves the check for initrd address to the same calculation-loop in bootmem_init() (arch/mips/kernel/setup.c), which also accounts for kernel code location. This should result in mapstart located starting from the first PFN area after kernel code AND initrd. Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com> Cc: linux-mips@linux-mips.org Cc: David Daney <david.daney@cavium.com> Cc: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> Cc: Huacai Chen <chenhc@lemote.com> Cc: Andreas Herrmann <andreas.herrmann@caviumnetworks.com> Cc: Joe Perches <joe@perches.com> Cc: Steven J. Hill <Steven.Hill@imgtec.com> Cc: Yusuf Khan <yusuf.khan@nokia.com> Cc: Michael Kreuzer <michael.kreuzer@nokia.com> Cc: Aaro Koskinen <aaro.koskinen@iki.fi> Patchwork: https://patchwork.linux-mips.org/patch/10594/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2015-07-02 23:16:01 +08:00
if (initrd_end && end <= (unsigned long)PFN_UP(__pa(initrd_end)))
continue;
#endif
}
if (min_low_pfn >= max_low_pfn)
panic("Incorrect memory mapping !!!");
#ifdef CONFIG_MIPS_AUTO_PFN_OFFSET
ARCH_PFN_OFFSET = PFN_UP(ramstart);
#else
/*
* Reserve any memory between the start of RAM and PHYS_OFFSET
*/
if (ramstart > PHYS_OFFSET) {
add_memory_region(PHYS_OFFSET, ramstart - PHYS_OFFSET,
BOOT_MEM_RESERVED);
memblock_reserve(PHYS_OFFSET, ramstart - PHYS_OFFSET);
}
if (min_low_pfn > ARCH_PFN_OFFSET) {
pr_info("Wasting %lu bytes for tracking %lu unused pages\n",
(min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page),
min_low_pfn - ARCH_PFN_OFFSET);
} else if (ARCH_PFN_OFFSET - min_low_pfn > 0UL) {
pr_info("%lu free pages won't be used\n",
ARCH_PFN_OFFSET - min_low_pfn);
}
min_low_pfn = ARCH_PFN_OFFSET;
#endif
/*
* Determine low and high memory ranges
*/
max_pfn = max_low_pfn;
if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) {
#ifdef CONFIG_HIGHMEM
highstart_pfn = PFN_DOWN(HIGHMEM_START);
highend_pfn = max_low_pfn;
#endif
max_low_pfn = PFN_DOWN(HIGHMEM_START);
}
for (i = 0; i < boot_mem_map.nr_map; i++) {
unsigned long start, end;
start = PFN_UP(boot_mem_map.map[i].addr);
end = PFN_DOWN(boot_mem_map.map[i].addr
+ boot_mem_map.map[i].size);
if (start <= min_low_pfn)
start = min_low_pfn;
if (start >= end)
continue;
#ifndef CONFIG_HIGHMEM
if (end > max_low_pfn)
end = max_low_pfn;
/*
* ... finally, is the area going away?
*/
if (end <= start)
continue;
#endif
memblock_add_node(PFN_PHYS(start), PFN_PHYS(end - start), 0);
}
/*
* Register fully available low RAM pages with the bootmem allocator.
*/
for (i = 0; i < boot_mem_map.nr_map; i++) {
unsigned long start, end, size;
MIPS: Handle initmem in systems with kernel not in add_memory_region() mem This patch addresses a couple of related problems: 1) The kernel may reside in physical memory outside of the ranges set by plat_mem_setup(). If this is the case, init mem cannot be reused as it resides outside of the range of pages that the kernel memory allocators control. 2) initrd images might be loaded in physical memory outside of the ranges set by plat_mem_setup(). The memory likewise cannot be reused. The patch doesn't handle this specific case, but the infrastructure is useful for future patches that do. The crux of the problem is that there are memory regions that need be memory_present(), but that cannot be free_bootmem() at the time of arch_mem_init(). We create a new type of memory (BOOT_MEM_INIT_RAM) for use with add_memory_region(). Then arch_mem_init() adds the init mem with this type if the init mem is not already covered by existing ranges. When memory is being freed into the bootmem allocator, we skip the BOOT_MEM_INIT_RAM ranges so they are not clobbered, but we do signal them as memory_present(). This way when they are later freed, the necessary memory manager structures have initialized and the Sparse allocater is prevented from crashing. The Octeon specific code that handled this case is removed, because the new general purpose code handles the case. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1988/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2011-11-22 22:38:03 +08:00
start = PFN_UP(boot_mem_map.map[i].addr);
end = PFN_DOWN(boot_mem_map.map[i].addr
+ boot_mem_map.map[i].size);
/*
* Reserve usable memory.
*/
MIPS: Handle initmem in systems with kernel not in add_memory_region() mem This patch addresses a couple of related problems: 1) The kernel may reside in physical memory outside of the ranges set by plat_mem_setup(). If this is the case, init mem cannot be reused as it resides outside of the range of pages that the kernel memory allocators control. 2) initrd images might be loaded in physical memory outside of the ranges set by plat_mem_setup(). The memory likewise cannot be reused. The patch doesn't handle this specific case, but the infrastructure is useful for future patches that do. The crux of the problem is that there are memory regions that need be memory_present(), but that cannot be free_bootmem() at the time of arch_mem_init(). We create a new type of memory (BOOT_MEM_INIT_RAM) for use with add_memory_region(). Then arch_mem_init() adds the init mem with this type if the init mem is not already covered by existing ranges. When memory is being freed into the bootmem allocator, we skip the BOOT_MEM_INIT_RAM ranges so they are not clobbered, but we do signal them as memory_present(). This way when they are later freed, the necessary memory manager structures have initialized and the Sparse allocater is prevented from crashing. The Octeon specific code that handled this case is removed, because the new general purpose code handles the case. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1988/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2011-11-22 22:38:03 +08:00
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RAM:
break;
case BOOT_MEM_INIT_RAM:
memory_present(0, start, end);
continue;
MIPS: Handle initmem in systems with kernel not in add_memory_region() mem This patch addresses a couple of related problems: 1) The kernel may reside in physical memory outside of the ranges set by plat_mem_setup(). If this is the case, init mem cannot be reused as it resides outside of the range of pages that the kernel memory allocators control. 2) initrd images might be loaded in physical memory outside of the ranges set by plat_mem_setup(). The memory likewise cannot be reused. The patch doesn't handle this specific case, but the infrastructure is useful for future patches that do. The crux of the problem is that there are memory regions that need be memory_present(), but that cannot be free_bootmem() at the time of arch_mem_init(). We create a new type of memory (BOOT_MEM_INIT_RAM) for use with add_memory_region(). Then arch_mem_init() adds the init mem with this type if the init mem is not already covered by existing ranges. When memory is being freed into the bootmem allocator, we skip the BOOT_MEM_INIT_RAM ranges so they are not clobbered, but we do signal them as memory_present(). This way when they are later freed, the necessary memory manager structures have initialized and the Sparse allocater is prevented from crashing. The Octeon specific code that handled this case is removed, because the new general purpose code handles the case. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1988/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2011-11-22 22:38:03 +08:00
default:
/* Not usable memory */
if (start > min_low_pfn && end < max_low_pfn)
memblock_reserve(boot_mem_map.map[i].addr,
boot_mem_map.map[i].size);
MIPS: Handle initmem in systems with kernel not in add_memory_region() mem This patch addresses a couple of related problems: 1) The kernel may reside in physical memory outside of the ranges set by plat_mem_setup(). If this is the case, init mem cannot be reused as it resides outside of the range of pages that the kernel memory allocators control. 2) initrd images might be loaded in physical memory outside of the ranges set by plat_mem_setup(). The memory likewise cannot be reused. The patch doesn't handle this specific case, but the infrastructure is useful for future patches that do. The crux of the problem is that there are memory regions that need be memory_present(), but that cannot be free_bootmem() at the time of arch_mem_init(). We create a new type of memory (BOOT_MEM_INIT_RAM) for use with add_memory_region(). Then arch_mem_init() adds the init mem with this type if the init mem is not already covered by existing ranges. When memory is being freed into the bootmem allocator, we skip the BOOT_MEM_INIT_RAM ranges so they are not clobbered, but we do signal them as memory_present(). This way when they are later freed, the necessary memory manager structures have initialized and the Sparse allocater is prevented from crashing. The Octeon specific code that handled this case is removed, because the new general purpose code handles the case. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1988/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2011-11-22 22:38:03 +08:00
continue;
}
/*
* We are rounding up the start address of usable memory
* and at the end of the usable range downwards.
*/
if (start >= max_low_pfn)
continue;
if (start < reserved_end)
start = reserved_end;
if (end > max_low_pfn)
end = max_low_pfn;
/*
* ... finally, is the area going away?
*/
if (end <= start)
continue;
size = end - start;
/* Register lowmem ranges */
memory_present(0, start, end);
}
#ifdef CONFIG_RELOCATABLE
/*
* The kernel reserves all memory below its _end symbol as bootmem,
* but the kernel may now be at a much higher address. The memory
* between the original and new locations may be returned to the system.
*/
if (__pa_symbol(_text) > __pa_symbol(VMLINUX_LOAD_ADDRESS)) {
unsigned long offset;
extern void show_kernel_relocation(const char *level);
offset = __pa_symbol(_text) - __pa_symbol(VMLINUX_LOAD_ADDRESS);
memblock: replace free_bootmem{_node} with memblock_free The free_bootmem and free_bootmem_node are merely wrappers for memblock_free. Replace their usage with a call to memblock_free using the following semantic patch: @@ expression e1, e2, e3; @@ ( - free_bootmem(e1, e2) + memblock_free(e1, e2) | - free_bootmem_node(e1, e2, e3) + memblock_free(e2, e3) ) Link: http://lkml.kernel.org/r/1536927045-23536-24-git-send-email-rppt@linux.vnet.ibm.com Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com> Acked-by: Michal Hocko <mhocko@suse.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Chris Zankel <chris@zankel.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Greentime Hu <green.hu@gmail.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Guan Xuetao <gxt@pku.edu.cn> Cc: Ingo Molnar <mingo@redhat.com> Cc: "James E.J. Bottomley" <jejb@parisc-linux.org> Cc: Jonas Bonn <jonas@southpole.se> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Ley Foon Tan <lftan@altera.com> Cc: Mark Salter <msalter@redhat.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Matt Turner <mattst88@gmail.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Michal Simek <monstr@monstr.eu> Cc: Palmer Dabbelt <palmer@sifive.com> Cc: Paul Burton <paul.burton@mips.com> Cc: Richard Kuo <rkuo@codeaurora.org> Cc: Richard Weinberger <richard@nod.at> Cc: Rich Felker <dalias@libc.org> Cc: Russell King <linux@armlinux.org.uk> Cc: Serge Semin <fancer.lancer@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Luck <tony.luck@intel.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-31 06:09:21 +08:00
memblock_free(__pa_symbol(VMLINUX_LOAD_ADDRESS), offset);
#if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO)
/*
* This information is necessary when debugging the kernel
* But is a security vulnerability otherwise!
*/
show_kernel_relocation(KERN_INFO);
#endif
}
#endif
/*
* Reserve initrd memory if needed.
*/
finalize_initrd();
}
#endif /* CONFIG_SGI_IP27 */
static int usermem __initdata;
static int __init early_parse_mem(char *p)
{
phys_addr_t start, size;
/*
* If a user specifies memory size, we
* blow away any automatically generated
* size.
*/
if (usermem == 0) {
boot_mem_map.nr_map = 0;
usermem = 1;
}
start = 0;
size = memparse(p, &p);
if (*p == '@')
start = memparse(p + 1, &p);
add_memory_region(start, size, BOOT_MEM_RAM);
return 0;
}
early_param("mem", early_parse_mem);
static int __init early_parse_memmap(char *p)
{
char *oldp;
u64 start_at, mem_size;
if (!p)
return -EINVAL;
if (!strncmp(p, "exactmap", 8)) {
pr_err("\"memmap=exactmap\" invalid on MIPS\n");
return 0;
}
oldp = p;
mem_size = memparse(p, &p);
if (p == oldp)
return -EINVAL;
if (*p == '@') {
start_at = memparse(p+1, &p);
add_memory_region(start_at, mem_size, BOOT_MEM_RAM);
} else if (*p == '#') {
pr_err("\"memmap=nn#ss\" (force ACPI data) invalid on MIPS\n");
return -EINVAL;
} else if (*p == '$') {
start_at = memparse(p+1, &p);
add_memory_region(start_at, mem_size, BOOT_MEM_RESERVED);
} else {
pr_err("\"memmap\" invalid format!\n");
return -EINVAL;
}
if (*p == '\0') {
usermem = 1;
return 0;
} else
return -EINVAL;
}
early_param("memmap", early_parse_memmap);
#ifdef CONFIG_PROC_VMCORE
unsigned long setup_elfcorehdr, setup_elfcorehdr_size;
static int __init early_parse_elfcorehdr(char *p)
{
int i;
setup_elfcorehdr = memparse(p, &p);
for (i = 0; i < boot_mem_map.nr_map; i++) {
unsigned long start = boot_mem_map.map[i].addr;
unsigned long end = (boot_mem_map.map[i].addr +
boot_mem_map.map[i].size);
if (setup_elfcorehdr >= start && setup_elfcorehdr < end) {
/*
* Reserve from the elf core header to the end of
* the memory segment, that should all be kdump
* reserved memory.
*/
setup_elfcorehdr_size = end - setup_elfcorehdr;
break;
}
}
/*
* If we don't find it in the memory map, then we shouldn't
* have to worry about it, as the new kernel won't use it.
*/
return 0;
}
early_param("elfcorehdr", early_parse_elfcorehdr);
#endif
static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
{
phys_addr_t size;
int i;
MIPS: Handle initmem in systems with kernel not in add_memory_region() mem This patch addresses a couple of related problems: 1) The kernel may reside in physical memory outside of the ranges set by plat_mem_setup(). If this is the case, init mem cannot be reused as it resides outside of the range of pages that the kernel memory allocators control. 2) initrd images might be loaded in physical memory outside of the ranges set by plat_mem_setup(). The memory likewise cannot be reused. The patch doesn't handle this specific case, but the infrastructure is useful for future patches that do. The crux of the problem is that there are memory regions that need be memory_present(), but that cannot be free_bootmem() at the time of arch_mem_init(). We create a new type of memory (BOOT_MEM_INIT_RAM) for use with add_memory_region(). Then arch_mem_init() adds the init mem with this type if the init mem is not already covered by existing ranges. When memory is being freed into the bootmem allocator, we skip the BOOT_MEM_INIT_RAM ranges so they are not clobbered, but we do signal them as memory_present(). This way when they are later freed, the necessary memory manager structures have initialized and the Sparse allocater is prevented from crashing. The Octeon specific code that handled this case is removed, because the new general purpose code handles the case. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1988/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2011-11-22 22:38:03 +08:00
size = end - mem;
if (!size)
return;
/* Make sure it is in the boot_mem_map */
for (i = 0; i < boot_mem_map.nr_map; i++) {
if (mem >= boot_mem_map.map[i].addr &&
mem < (boot_mem_map.map[i].addr +
boot_mem_map.map[i].size))
return;
}
add_memory_region(mem, size, type);
}
MIPS: Handle initmem in systems with kernel not in add_memory_region() mem This patch addresses a couple of related problems: 1) The kernel may reside in physical memory outside of the ranges set by plat_mem_setup(). If this is the case, init mem cannot be reused as it resides outside of the range of pages that the kernel memory allocators control. 2) initrd images might be loaded in physical memory outside of the ranges set by plat_mem_setup(). The memory likewise cannot be reused. The patch doesn't handle this specific case, but the infrastructure is useful for future patches that do. The crux of the problem is that there are memory regions that need be memory_present(), but that cannot be free_bootmem() at the time of arch_mem_init(). We create a new type of memory (BOOT_MEM_INIT_RAM) for use with add_memory_region(). Then arch_mem_init() adds the init mem with this type if the init mem is not already covered by existing ranges. When memory is being freed into the bootmem allocator, we skip the BOOT_MEM_INIT_RAM ranges so they are not clobbered, but we do signal them as memory_present(). This way when they are later freed, the necessary memory manager structures have initialized and the Sparse allocater is prevented from crashing. The Octeon specific code that handled this case is removed, because the new general purpose code handles the case. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1988/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2011-11-22 22:38:03 +08:00
#ifdef CONFIG_KEXEC
static inline unsigned long long get_total_mem(void)
{
unsigned long long total;
total = max_pfn - min_low_pfn;
return total << PAGE_SHIFT;
}
static void __init mips_parse_crashkernel(void)
{
unsigned long long total_mem;
unsigned long long crash_size, crash_base;
int ret;
total_mem = get_total_mem();
ret = parse_crashkernel(boot_command_line, total_mem,
&crash_size, &crash_base);
if (ret != 0 || crash_size <= 0)
return;
if (!memory_region_available(crash_base, crash_size)) {
pr_warn("Invalid memory region reserved for crash kernel\n");
return;
}
crashk_res.start = crash_base;
crashk_res.end = crash_base + crash_size - 1;
}
static void __init request_crashkernel(struct resource *res)
{
int ret;
if (crashk_res.start == crashk_res.end)
return;
ret = request_resource(res, &crashk_res);
if (!ret)
pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
(unsigned long)((crashk_res.end -
crashk_res.start + 1) >> 20),
(unsigned long)(crashk_res.start >> 20));
}
#else /* !defined(CONFIG_KEXEC) */
static void __init mips_parse_crashkernel(void)
{
}
static void __init request_crashkernel(struct resource *res)
{
}
#endif /* !defined(CONFIG_KEXEC) */
#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND)
#define BUILTIN_EXTEND_WITH_PROM \
IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND)
/*
* arch_mem_init - initialize memory management subsystem
*
* o plat_mem_setup() detects the memory configuration and will record detected
* memory areas using add_memory_region.
*
* At this stage the memory configuration of the system is known to the
* kernel but generic memory management system is still entirely uninitialized.
*
* o bootmem_init()
* o sparse_init()
* o paging_init()
* o dma_contiguous_reserve()
*
* At this stage the bootmem allocator is ready to use.
*
* NOTE: historically plat_mem_setup did the entire platform initialization.
* This was rather impractical because it meant plat_mem_setup had to
* get away without any kind of memory allocator. To keep old code from
* breaking plat_setup was just renamed to plat_mem_setup and a second platform
* initialization hook for anything else was introduced.
*/
static void __init arch_mem_init(char **cmdline_p)
{
struct memblock_region *reg;
extern void plat_mem_setup(void);
MIPS: Fix CONFIG_CMDLINE handling Commit 8ce355cf2e38 ("MIPS: Setup boot_command_line before plat_mem_setup") fixed a problem for systems which have CONFIG_CMDLINE_BOOL=y & use a DT with a chosen node that has either no bootargs property or an empty one. In this configuration early_init_dt_scan_chosen() copies CONFIG_CMDLINE into boot_command_line, but the MIPS code doesn't know this so it appends CONFIG_CMDLINE (via builtin_cmdline) to boot_command_line again. The result is that boot_command_line contains the arguments from CONFIG_CMDLINE twice. That commit took the approach of simply setting up boot_command_line from the MIPS code before early_init_dt_scan_chosen() runs, causing it not to copy CONFIG_CMDLINE to boot_command_line if a chosen node with no bootargs property is found. Unfortunately this is problematic for systems which do have a non-empty bootargs property & CONFIG_CMDLINE_BOOL=y. There early_init_dt_scan_chosen() will overwrite boot_command_line with the arguments from DT, which means we lose those from CONFIG_CMDLINE entirely. This breaks CONFIG_MIPS_CMDLINE_DTB_EXTEND. If we have CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER or CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND selected and the DT has a bootargs property which we should ignore, it will instead be honoured breaking those configurations too. Fix this by reverting commit 8ce355cf2e38 ("MIPS: Setup boot_command_line before plat_mem_setup") to restore the former behaviour, and fixing the CONFIG_CMDLINE duplication issue by initializing boot_command_line to a non-empty string that early_init_dt_scan_chosen() will not overwrite with CONFIG_CMDLINE. This is a little ugly, but cleanup in this area is on its way. In the meantime this is at least easy to backport & contains the ugliness within arch/mips/. Signed-off-by: Paul Burton <paul.burton@mips.com> Fixes: 8ce355cf2e38 ("MIPS: Setup boot_command_line before plat_mem_setup") References: https://patchwork.linux-mips.org/patch/18804/ Patchwork: https://patchwork.linux-mips.org/patch/20813/ Cc: Frank Rowand <frowand.list@gmail.com> Cc: Jaedon Shin <jaedon.shin@gmail.com> Cc: Mathieu Malaterre <malat@debian.org> Cc: Rob Herring <robh+dt@kernel.org> Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org # v4.16+
2018-09-28 06:59:18 +08:00
/*
* Initialize boot_command_line to an innocuous but non-empty string in
* order to prevent early_init_dt_scan_chosen() from copying
* CONFIG_CMDLINE into it without our knowledge. We handle
* CONFIG_CMDLINE ourselves below & don't want to duplicate its
* content because repeating arguments can be problematic.
*/
strlcpy(boot_command_line, " ", COMMAND_LINE_SIZE);
/* call board setup routine */
plat_mem_setup();
memblock_set_bottom_up(true);
MIPS: Fix CONFIG_CMDLINE handling Commit 8ce355cf2e38 ("MIPS: Setup boot_command_line before plat_mem_setup") fixed a problem for systems which have CONFIG_CMDLINE_BOOL=y & use a DT with a chosen node that has either no bootargs property or an empty one. In this configuration early_init_dt_scan_chosen() copies CONFIG_CMDLINE into boot_command_line, but the MIPS code doesn't know this so it appends CONFIG_CMDLINE (via builtin_cmdline) to boot_command_line again. The result is that boot_command_line contains the arguments from CONFIG_CMDLINE twice. That commit took the approach of simply setting up boot_command_line from the MIPS code before early_init_dt_scan_chosen() runs, causing it not to copy CONFIG_CMDLINE to boot_command_line if a chosen node with no bootargs property is found. Unfortunately this is problematic for systems which do have a non-empty bootargs property & CONFIG_CMDLINE_BOOL=y. There early_init_dt_scan_chosen() will overwrite boot_command_line with the arguments from DT, which means we lose those from CONFIG_CMDLINE entirely. This breaks CONFIG_MIPS_CMDLINE_DTB_EXTEND. If we have CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER or CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND selected and the DT has a bootargs property which we should ignore, it will instead be honoured breaking those configurations too. Fix this by reverting commit 8ce355cf2e38 ("MIPS: Setup boot_command_line before plat_mem_setup") to restore the former behaviour, and fixing the CONFIG_CMDLINE duplication issue by initializing boot_command_line to a non-empty string that early_init_dt_scan_chosen() will not overwrite with CONFIG_CMDLINE. This is a little ugly, but cleanup in this area is on its way. In the meantime this is at least easy to backport & contains the ugliness within arch/mips/. Signed-off-by: Paul Burton <paul.burton@mips.com> Fixes: 8ce355cf2e38 ("MIPS: Setup boot_command_line before plat_mem_setup") References: https://patchwork.linux-mips.org/patch/18804/ Patchwork: https://patchwork.linux-mips.org/patch/20813/ Cc: Frank Rowand <frowand.list@gmail.com> Cc: Jaedon Shin <jaedon.shin@gmail.com> Cc: Mathieu Malaterre <malat@debian.org> Cc: Rob Herring <robh+dt@kernel.org> Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org # v4.16+
2018-09-28 06:59:18 +08:00
/*
* Make sure all kernel memory is in the maps. The "UP" and
* "DOWN" are opposite for initdata since if it crosses over
* into another memory section you don't want that to be
* freed when the initdata is freed.
*/
arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
BOOT_MEM_RAM);
arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
BOOT_MEM_INIT_RAM);
pr_info("Determined physical RAM map:\n");
print_memory_map();
#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else
if ((USE_PROM_CMDLINE && arcs_cmdline[0]) ||
(USE_DTB_CMDLINE && !boot_command_line[0]))
strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
if (EXTEND_WITH_PROM && arcs_cmdline[0]) {
if (boot_command_line[0])
strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
}
#if defined(CONFIG_CMDLINE_BOOL)
if (builtin_cmdline[0]) {
if (boot_command_line[0])
strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
}
if (BUILTIN_EXTEND_WITH_PROM && arcs_cmdline[0]) {
if (boot_command_line[0])
strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
}
#endif
#endif
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
parse_early_param();
if (usermem) {
pr_info("User-defined physical RAM map:\n");
print_memory_map();
}
early_init_fdt_reserve_self();
early_init_fdt_scan_reserved_mem();
bootmem_init();
/*
* Prevent memblock from allocating high memory.
* This cannot be done before max_low_pfn is detected, so up
* to this point is possible to only reserve physical memory
memblock: remove _virt from APIs returning virtual address The conversion is done using sed -i 's@memblock_virt_alloc@memblock_alloc@g' \ $(git grep -l memblock_virt_alloc) Link: http://lkml.kernel.org/r/1536927045-23536-8-git-send-email-rppt@linux.vnet.ibm.com Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Chris Zankel <chris@zankel.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Greentime Hu <green.hu@gmail.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Guan Xuetao <gxt@pku.edu.cn> Cc: Ingo Molnar <mingo@redhat.com> Cc: "James E.J. Bottomley" <jejb@parisc-linux.org> Cc: Jonas Bonn <jonas@southpole.se> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Ley Foon Tan <lftan@altera.com> Cc: Mark Salter <msalter@redhat.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Matt Turner <mattst88@gmail.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Michal Hocko <mhocko@suse.com> Cc: Michal Simek <monstr@monstr.eu> Cc: Palmer Dabbelt <palmer@sifive.com> Cc: Paul Burton <paul.burton@mips.com> Cc: Richard Kuo <rkuo@codeaurora.org> Cc: Richard Weinberger <richard@nod.at> Cc: Rich Felker <dalias@libc.org> Cc: Russell King <linux@armlinux.org.uk> Cc: Serge Semin <fancer.lancer@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Luck <tony.luck@intel.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-31 06:08:04 +08:00
* with memblock_reserve; memblock_alloc* can be used
* only after this point
*/
memblock_set_current_limit(PFN_PHYS(max_low_pfn));
#ifdef CONFIG_PROC_VMCORE
if (setup_elfcorehdr && setup_elfcorehdr_size) {
printk(KERN_INFO "kdump reserved memory at %lx-%lx\n",
setup_elfcorehdr, setup_elfcorehdr_size);
memblock_reserve(setup_elfcorehdr, setup_elfcorehdr_size);
}
#endif
mips_parse_crashkernel();
#ifdef CONFIG_KEXEC
if (crashk_res.start != crashk_res.end)
memblock_reserve(crashk_res.start,
crashk_res.end - crashk_res.start + 1);
#endif
device_tree_init();
sparse_init();
plat_swiotlb_setup();
dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
/* Tell bootmem about cma reserved memblock section */
for_each_memblock(reserved, reg)
if (reg->size != 0)
memblock_reserve(reg->base, reg->size);
reserve_bootmem_region(__pa_symbol(&__nosave_begin),
__pa_symbol(&__nosave_end)); /* Reserve for hibernation */
}
static void __init resource_init(void)
{
int i;
if (UNCAC_BASE != IO_BASE)
return;
code_resource.start = __pa_symbol(&_text);
code_resource.end = __pa_symbol(&_etext) - 1;
data_resource.start = __pa_symbol(&_etext);
data_resource.end = __pa_symbol(&_edata) - 1;
bss_resource.start = __pa_symbol(&__bss_start);
bss_resource.end = __pa_symbol(&__bss_stop) - 1;
for (i = 0; i < boot_mem_map.nr_map; i++) {
struct resource *res;
unsigned long start, end;
start = boot_mem_map.map[i].addr;
end = boot_mem_map.map[i].addr + boot_mem_map.map[i].size - 1;
if (start >= HIGHMEM_START)
continue;
if (end >= HIGHMEM_START)
end = HIGHMEM_START - 1;
memblock: stop using implicit alignment to SMP_CACHE_BYTES When a memblock allocation APIs are called with align = 0, the alignment is implicitly set to SMP_CACHE_BYTES. Implicit alignment is done deep in the memblock allocator and it can come as a surprise. Not that such an alignment would be wrong even when used incorrectly but it is better to be explicit for the sake of clarity and the prinicple of the least surprise. Replace all such uses of memblock APIs with the 'align' parameter explicitly set to SMP_CACHE_BYTES and stop implicit alignment assignment in the memblock internal allocation functions. For the case when memblock APIs are used via helper functions, e.g. like iommu_arena_new_node() in Alpha, the helper functions were detected with Coccinelle's help and then manually examined and updated where appropriate. The direct memblock APIs users were updated using the semantic patch below: @@ expression size, min_addr, max_addr, nid; @@ ( | - memblock_alloc_try_nid_raw(size, 0, min_addr, max_addr, nid) + memblock_alloc_try_nid_raw(size, SMP_CACHE_BYTES, min_addr, max_addr, nid) | - memblock_alloc_try_nid_nopanic(size, 0, min_addr, max_addr, nid) + memblock_alloc_try_nid_nopanic(size, SMP_CACHE_BYTES, min_addr, max_addr, nid) | - memblock_alloc_try_nid(size, 0, min_addr, max_addr, nid) + memblock_alloc_try_nid(size, SMP_CACHE_BYTES, min_addr, max_addr, nid) | - memblock_alloc(size, 0) + memblock_alloc(size, SMP_CACHE_BYTES) | - memblock_alloc_raw(size, 0) + memblock_alloc_raw(size, SMP_CACHE_BYTES) | - memblock_alloc_from(size, 0, min_addr) + memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr) | - memblock_alloc_nopanic(size, 0) + memblock_alloc_nopanic(size, SMP_CACHE_BYTES) | - memblock_alloc_low(size, 0) + memblock_alloc_low(size, SMP_CACHE_BYTES) | - memblock_alloc_low_nopanic(size, 0) + memblock_alloc_low_nopanic(size, SMP_CACHE_BYTES) | - memblock_alloc_from_nopanic(size, 0, min_addr) + memblock_alloc_from_nopanic(size, SMP_CACHE_BYTES, min_addr) | - memblock_alloc_node(size, 0, nid) + memblock_alloc_node(size, SMP_CACHE_BYTES, nid) ) [mhocko@suse.com: changelog update] [akpm@linux-foundation.org: coding-style fixes] [rppt@linux.ibm.com: fix missed uses of implicit alignment] Link: http://lkml.kernel.org/r/20181016133656.GA10925@rapoport-lnx Link: http://lkml.kernel.org/r/1538687224-17535-1-git-send-email-rppt@linux.vnet.ibm.com Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com> Suggested-by: Michal Hocko <mhocko@suse.com> Acked-by: Paul Burton <paul.burton@mips.com> [MIPS] Acked-by: Michael Ellerman <mpe@ellerman.id.au> [powerpc] Acked-by: Michal Hocko <mhocko@suse.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Chris Zankel <chris@zankel.net> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Guan Xuetao <gxt@pku.edu.cn> Cc: Ingo Molnar <mingo@redhat.com> Cc: Matt Turner <mattst88@gmail.com> Cc: Michal Simek <monstr@monstr.eu> Cc: Richard Weinberger <richard@nod.at> Cc: Russell King <linux@armlinux.org.uk> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Luck <tony.luck@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-31 06:09:57 +08:00
res = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);
res->start = start;
res->end = end;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RAM:
MIPS: Handle initmem in systems with kernel not in add_memory_region() mem This patch addresses a couple of related problems: 1) The kernel may reside in physical memory outside of the ranges set by plat_mem_setup(). If this is the case, init mem cannot be reused as it resides outside of the range of pages that the kernel memory allocators control. 2) initrd images might be loaded in physical memory outside of the ranges set by plat_mem_setup(). The memory likewise cannot be reused. The patch doesn't handle this specific case, but the infrastructure is useful for future patches that do. The crux of the problem is that there are memory regions that need be memory_present(), but that cannot be free_bootmem() at the time of arch_mem_init(). We create a new type of memory (BOOT_MEM_INIT_RAM) for use with add_memory_region(). Then arch_mem_init() adds the init mem with this type if the init mem is not already covered by existing ranges. When memory is being freed into the bootmem allocator, we skip the BOOT_MEM_INIT_RAM ranges so they are not clobbered, but we do signal them as memory_present(). This way when they are later freed, the necessary memory manager structures have initialized and the Sparse allocater is prevented from crashing. The Octeon specific code that handled this case is removed, because the new general purpose code handles the case. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1988/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2011-11-22 22:38:03 +08:00
case BOOT_MEM_INIT_RAM:
case BOOT_MEM_ROM_DATA:
res->name = "System RAM";
res->flags |= IORESOURCE_SYSRAM;
break;
case BOOT_MEM_RESERVED:
default:
res->name = "reserved";
}
request_resource(&iomem_resource, res);
/*
* We don't know which RAM region contains kernel data,
* so we try it repeatedly and let the resource manager
* test it.
*/
request_resource(res, &code_resource);
request_resource(res, &data_resource);
request_resource(res, &bss_resource);
request_crashkernel(res);
}
}
#ifdef CONFIG_SMP
static void __init prefill_possible_map(void)
{
int i, possible = num_possible_cpus();
if (possible > nr_cpu_ids)
possible = nr_cpu_ids;
for (i = 0; i < possible; i++)
set_cpu_possible(i, true);
for (; i < NR_CPUS; i++)
set_cpu_possible(i, false);
nr_cpu_ids = possible;
}
#else
static inline void prefill_possible_map(void) {}
#endif
void __init setup_arch(char **cmdline_p)
{
cpu_probe();
MIPS: Fix early CM probing Commit c014d164f21d ("MIPS: Add platform callback before initializing the L2 cache") added a platform_early_l2_init function in order to allow platforms to probe for the CM before L2 initialisation is performed, so that CM GCRs are available to mips_sc_probe. That commit actually fails to do anything useful, since it checks mips_cm_revision to determine whether it should call mips_cm_probe but the result of mips_cm_revision will always be 0 until mips_cm_probe has been called. Thus the "early" mips_cm_probe call never occurs. Fix this & drop the useless weak platform_early_l2_init function by simply calling mips_cm_probe from setup_arch. For platforms that don't select CONFIG_MIPS_CM this will be a no-op, and for those that do it removes the requirement for them to call mips_cm_probe manually (although doing so isn't harmful for now). Signed-off-by: Paul Burton <paul.burton@imgtec.com> Reviewed-by: Alexander Sverdlin <alexander.sverdlin@nokia.com> Cc: Andrzej Hajda <a.hajda@samsung.com> Cc: Aaro Koskinen <aaro.koskinen@nokia.com> Cc: Masahiro Yamada <yamada.masahiro@socionext.com> Cc: Rob Herring <robh@kernel.org> Cc: Peter Hurley <peter@hurleysoftware.com> Cc: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> Cc: Jaedon Shin <jaedon.shin@gmail.com> Cc: James Hogan <james.hogan@imgtec.com> Cc: Jonas Gorski <jogo@openwrt.org> Cc: Markos Chandras <markos.chandras@imgtec.com> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12475/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2016-02-09 01:46:31 +08:00
mips_cm_probe();
prom_init();
setup_early_fdc_console();
#ifdef CONFIG_EARLY_PRINTK
setup_early_printk();
#endif
cpu_report();
[MIPS] R4000/R4400 errata workarounds This is the gereric part of R4000/R4400 errata workarounds. They include compiler and assembler support as well as some source code modifications to address the problems with some combinations of multiply/divide+shift instructions as well as the daddi and daddiu instructions. Changes included are as follows: 1. New Kconfig options to select workarounds by platforms as necessary. 2. Arch top-level Makefile to pass necessary options to the compiler; also incompatible configurations are detected (-mno-sym32 unsupported as horribly intrusive for little gain). 3. Bug detection updated and shuffled -- the multiply/divide+shift problem is lethal enough that if not worked around it makes the kernel crash in time_init() because of a division by zero; the daddiu erratum might also trigger early potentially, though I have not observed it. On the other hand the daddi detection code requires the exception subsystem to have been initialised (and is there mainly for information). 4. r4k_daddiu_bug() added so that the existence of the erratum can be queried by code at the run time as necessary; useful for generated code like TLB fault and copy/clear page handlers. 5. __udelay() updated as it uses multiplication in inline assembly. Note that -mdaddi requires modified toolchain (which has been maintained by myself and available from my site for ~4years now -- versions covered are GCC 2.95.4 - 4.1.2 and binutils from 2.13 onwards). The -mfix-r4000 and -mfix-r4400 have been standard for a while though. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2007-10-23 19:43:11 +08:00
check_bugs_early();
#if defined(CONFIG_VT)
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
#endif
arch_mem_init(cmdline_p);
resource_init();
plat_smp_setup();
prefill_possible_map();
cpu_cache_init();
MIPS: Fix detection of unsupported highmem with cache aliases The paging_init() function contains code which detects that highmem is in use but unsupported due to dcache aliasing. However this code was ineffective because it was being run before the caches are probed, meaning that cpu_has_dc_aliases would always evaluate to false (unless a platform overrides it to a compile-time constant) and the detection of the unsupported case is never triggered. The kernel would then go on to attempt to use highmem & either hit coherency issues or trigger the BUG_ON in flush_kernel_dcache_page(). Fix this by running paging_init() later than cpu_cache_init(), such that the cpu_has_dc_aliases macro will evaluate correctly & the unsupported highmem case will be detected successfully. This then leads to a formerly hidden issue in that mem_init_free_highmem() will attempt to free all highmem pages, even though we're avoiding use of them & don't have valid page structs for them. This leads to an invalid pointer dereference & a TLB exception. Avoid this by skipping the loop in mem_init_free_highmem() if cpu_has_dc_aliases evaluates true. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: Rabin Vincent <rabinv@axis.com> Cc: Matt Redfearn <matt.redfearn@imgtec.com> Cc: Jerome Marchand <jmarchan@redhat.com> Cc: Alexander Sverdlin <alexander.sverdlin@gmail.com> Cc: Aurelien Jarno <aurelien@aurel32.net> Cc: Jaedon Shin <jaedon.shin@gmail.com> Cc: Toshi Kani <toshi.kani@hpe.com> Cc: James Hogan <james.hogan@imgtec.com> Cc: Sergey Ryazanov <ryazanov.s.a@gmail.com> Cc: Jonas Gorski <jogo@openwrt.org> Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14184/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2016-09-02 22:17:31 +08:00
paging_init();
}
unsigned long kernelsp[NR_CPUS];
unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
#ifdef CONFIG_USE_OF
unsigned long fw_passed_dtb;
#endif
#ifdef CONFIG_DEBUG_FS
struct dentry *mips_debugfs_dir;
static int __init debugfs_mips(void)
{
mips_debugfs_dir = debugfs_create_dir("mips", NULL);
return 0;
}
arch_initcall(debugfs_mips);
#endif
#ifdef CONFIG_DMA_MAYBE_COHERENT
/* User defined DMA coherency from command line. */
enum coherent_io_user_state coherentio = IO_COHERENCE_DEFAULT;
EXPORT_SYMBOL_GPL(coherentio);
int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */
static int __init setcoherentio(char *str)
{
coherentio = IO_COHERENCE_ENABLED;
pr_info("Hardware DMA cache coherency (command line)\n");
return 0;
}
early_param("coherentio", setcoherentio);
static int __init setnocoherentio(char *str)
{
coherentio = IO_COHERENCE_DISABLED;
pr_info("Software DMA cache coherency (command line)\n");
return 0;
}
early_param("nocoherentio", setnocoherentio);
#endif