2011-01-15 11:15:45 +01:00
|
|
|
/*
|
|
|
|
* linux/arch/unicore32/kernel/setup.c
|
|
|
|
*
|
|
|
|
* Code specific to PKUnity SoC and UniCore ISA
|
|
|
|
*
|
|
|
|
* Copyright (C) 2001-2010 GUAN Xue-tao
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/stddef.h>
|
|
|
|
#include <linux/ioport.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/utsname.h>
|
|
|
|
#include <linux/initrd.h>
|
|
|
|
#include <linux/console.h>
|
2018-10-30 23:09:49 +01:00
|
|
|
#include <linux/memblock.h>
|
2011-01-15 11:15:45 +01:00
|
|
|
#include <linux/seq_file.h>
|
|
|
|
#include <linux/screen_info.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/root_dev.h>
|
|
|
|
#include <linux/cpu.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/smp.h>
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/proc_fs.h>
|
|
|
|
#include <linux/elf.h>
|
|
|
|
#include <linux/io.h>
|
|
|
|
|
|
|
|
#include <asm/cputype.h>
|
|
|
|
#include <asm/sections.h>
|
|
|
|
#include <asm/setup.h>
|
|
|
|
#include <asm/cacheflush.h>
|
|
|
|
#include <asm/tlbflush.h>
|
|
|
|
#include <asm/traps.h>
|
2011-12-08 19:22:06 +01:00
|
|
|
#include <asm/memblock.h>
|
2011-01-15 11:15:45 +01:00
|
|
|
|
|
|
|
#include "setup.h"
|
|
|
|
|
|
|
|
#ifndef MEM_SIZE
|
|
|
|
#define MEM_SIZE (16*1024*1024)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct stack {
|
|
|
|
u32 irq[3];
|
|
|
|
u32 abt[3];
|
|
|
|
u32 und[3];
|
|
|
|
} ____cacheline_aligned;
|
|
|
|
|
|
|
|
static struct stack stacks[NR_CPUS];
|
|
|
|
|
2014-05-22 01:08:23 +02:00
|
|
|
#ifdef CONFIG_VGA_CONSOLE
|
|
|
|
struct screen_info screen_info;
|
|
|
|
#endif
|
|
|
|
|
2011-01-15 11:15:45 +01:00
|
|
|
char elf_platform[ELF_PLATFORM_SIZE];
|
|
|
|
EXPORT_SYMBOL(elf_platform);
|
|
|
|
|
|
|
|
static char __initdata cmd_line[COMMAND_LINE_SIZE];
|
|
|
|
|
|
|
|
static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Standard memory resources
|
|
|
|
*/
|
|
|
|
static struct resource mem_res[] = {
|
|
|
|
{
|
2011-12-13 00:04:29 +01:00
|
|
|
.name = "Kernel code",
|
2011-01-15 11:15:45 +01:00
|
|
|
.start = 0,
|
|
|
|
.end = 0,
|
2016-01-26 21:57:22 +01:00
|
|
|
.flags = IORESOURCE_SYSTEM_RAM
|
2011-01-15 11:15:45 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Kernel data",
|
|
|
|
.start = 0,
|
|
|
|
.end = 0,
|
2016-01-26 21:57:22 +01:00
|
|
|
.flags = IORESOURCE_SYSTEM_RAM
|
2011-01-15 11:15:45 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-04-01 10:38:59 +02:00
|
|
|
#define kernel_code mem_res[0]
|
|
|
|
#define kernel_data mem_res[1]
|
2011-01-15 11:15:45 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* These functions re-use the assembly code in head.S, which
|
|
|
|
* already provide the required functionality.
|
|
|
|
*/
|
|
|
|
static void __init setup_processor(void)
|
|
|
|
{
|
|
|
|
printk(KERN_DEFAULT "CPU: UniCore-II [%08x] revision %d, cr=%08lx\n",
|
|
|
|
uc32_cpuid, (int)(uc32_cpuid >> 16) & 15, cr_alignment);
|
|
|
|
|
|
|
|
sprintf(init_utsname()->machine, "puv3");
|
|
|
|
sprintf(elf_platform, "ucv2");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* cpu_init - initialise one CPU.
|
|
|
|
*
|
|
|
|
* cpu_init sets up the per-CPU stacks.
|
|
|
|
*/
|
|
|
|
void cpu_init(void)
|
|
|
|
{
|
|
|
|
unsigned int cpu = smp_processor_id();
|
|
|
|
struct stack *stk = &stacks[cpu];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* setup stacks for re-entrant exception handlers
|
|
|
|
*/
|
|
|
|
__asm__ (
|
|
|
|
"mov.a asr, %1\n\t"
|
|
|
|
"add sp, %0, %2\n\t"
|
|
|
|
"mov.a asr, %3\n\t"
|
|
|
|
"add sp, %0, %4\n\t"
|
|
|
|
"mov.a asr, %5\n\t"
|
|
|
|
"add sp, %0, %6\n\t"
|
|
|
|
"mov.a asr, %7"
|
|
|
|
:
|
|
|
|
: "r" (stk),
|
|
|
|
"r" (PSR_R_BIT | PSR_I_BIT | INTR_MODE),
|
|
|
|
"I" (offsetof(struct stack, irq[0])),
|
|
|
|
"r" (PSR_R_BIT | PSR_I_BIT | ABRT_MODE),
|
|
|
|
"I" (offsetof(struct stack, abt[0])),
|
|
|
|
"r" (PSR_R_BIT | PSR_I_BIT | EXTN_MODE),
|
|
|
|
"I" (offsetof(struct stack, und[0])),
|
|
|
|
"r" (PSR_R_BIT | PSR_I_BIT | PRIV_MODE)
|
|
|
|
: "r30", "cc");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __init uc32_add_memory(unsigned long start, unsigned long size)
|
|
|
|
{
|
|
|
|
struct membank *bank = &meminfo.bank[meminfo.nr_banks];
|
|
|
|
|
|
|
|
if (meminfo.nr_banks >= NR_BANKS) {
|
|
|
|
printk(KERN_CRIT "NR_BANKS too low, "
|
|
|
|
"ignoring memory at %#lx\n", start);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure that start/size are aligned to a page boundary.
|
|
|
|
* Size is appropriately rounded down, start is rounded up.
|
|
|
|
*/
|
|
|
|
size -= start & ~PAGE_MASK;
|
|
|
|
|
|
|
|
bank->start = PAGE_ALIGN(start);
|
|
|
|
bank->size = size & PAGE_MASK;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check whether this memory region has non-zero size or
|
|
|
|
* invalid node number.
|
|
|
|
*/
|
|
|
|
if (bank->size == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
meminfo.nr_banks++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pick out the memory size. We look for mem=size@start,
|
|
|
|
* where start and size are "size[KkMm]"
|
|
|
|
*/
|
|
|
|
static int __init early_mem(char *p)
|
|
|
|
{
|
|
|
|
static int usermem __initdata = 1;
|
|
|
|
unsigned long size, start;
|
|
|
|
char *endp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the user specifies memory size, we
|
|
|
|
* blow away any automatically generated
|
|
|
|
* size.
|
|
|
|
*/
|
|
|
|
if (usermem) {
|
|
|
|
usermem = 0;
|
|
|
|
meminfo.nr_banks = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = PHYS_OFFSET;
|
|
|
|
size = memparse(p, &endp);
|
|
|
|
if (*endp == '@')
|
|
|
|
start = memparse(endp + 1, NULL);
|
|
|
|
|
|
|
|
uc32_add_memory(start, size);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
early_param("mem", early_mem);
|
|
|
|
|
|
|
|
static void __init
|
|
|
|
request_standard_resources(struct meminfo *mi)
|
|
|
|
{
|
|
|
|
struct resource *res;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
kernel_code.start = virt_to_phys(_stext);
|
|
|
|
kernel_code.end = virt_to_phys(_etext - 1);
|
|
|
|
kernel_data.start = virt_to_phys(_sdata);
|
|
|
|
kernel_data.end = virt_to_phys(_end - 1);
|
|
|
|
|
|
|
|
for (i = 0; i < mi->nr_banks; i++) {
|
|
|
|
if (mi->bank[i].size == 0)
|
|
|
|
continue;
|
|
|
|
|
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-30 23:09:57 +01:00
|
|
|
res = memblock_alloc_low(sizeof(*res), SMP_CACHE_BYTES);
|
2019-03-12 07:30:31 +01:00
|
|
|
if (!res)
|
|
|
|
panic("%s: Failed to allocate %zu bytes align=%x\n",
|
|
|
|
__func__, sizeof(*res), SMP_CACHE_BYTES);
|
|
|
|
|
2011-01-15 11:15:45 +01:00
|
|
|
res->name = "System RAM";
|
|
|
|
res->start = mi->bank[i].start;
|
|
|
|
res->end = mi->bank[i].start + mi->bank[i].size - 1;
|
2016-01-26 21:57:22 +01:00
|
|
|
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
|
2011-01-15 11:15:45 +01:00
|
|
|
|
|
|
|
request_resource(&iomem_resource, res);
|
|
|
|
|
|
|
|
if (kernel_code.start >= res->start &&
|
|
|
|
kernel_code.end <= res->end)
|
|
|
|
request_resource(res, &kernel_code);
|
|
|
|
if (kernel_data.start >= res->start &&
|
|
|
|
kernel_data.end <= res->end)
|
|
|
|
request_resource(res, &kernel_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void (*init_machine)(void) __initdata;
|
|
|
|
|
|
|
|
static int __init customize_machine(void)
|
|
|
|
{
|
|
|
|
/* customizes platform devices, or adds new ones */
|
|
|
|
if (init_machine)
|
|
|
|
init_machine();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
arch_initcall(customize_machine);
|
|
|
|
|
|
|
|
void __init setup_arch(char **cmdline_p)
|
|
|
|
{
|
|
|
|
char *from = default_command_line;
|
|
|
|
|
|
|
|
setup_processor();
|
|
|
|
|
|
|
|
init_mm.start_code = (unsigned long) _stext;
|
|
|
|
init_mm.end_code = (unsigned long) _etext;
|
|
|
|
init_mm.end_data = (unsigned long) _edata;
|
|
|
|
init_mm.brk = (unsigned long) _end;
|
|
|
|
|
|
|
|
/* parse_early_param needs a boot_command_line */
|
|
|
|
strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
|
|
|
|
|
|
|
|
/* populate cmd_line too for later use, preserving boot_command_line */
|
|
|
|
strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
|
|
|
|
*cmdline_p = cmd_line;
|
|
|
|
|
|
|
|
parse_early_param();
|
|
|
|
|
|
|
|
uc32_memblock_init(&meminfo);
|
|
|
|
|
|
|
|
paging_init();
|
|
|
|
request_standard_resources(&meminfo);
|
|
|
|
|
|
|
|
cpu_init();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up various architecture-specific pointers
|
|
|
|
*/
|
|
|
|
init_machine = puv3_core_init;
|
|
|
|
|
|
|
|
#ifdef CONFIG_VT
|
|
|
|
#if defined(CONFIG_VGA_CONSOLE)
|
|
|
|
conswitchp = &vga_con;
|
|
|
|
#elif defined(CONFIG_DUMMY_CONSOLE)
|
|
|
|
conswitchp = &dummy_con;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
early_trap_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct cpu cpuinfo_unicore;
|
|
|
|
|
|
|
|
static int __init topology_init(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for_each_possible_cpu(i)
|
|
|
|
register_cpu(&cpuinfo_unicore, i);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
subsys_initcall(topology_init);
|
|
|
|
|
|
|
|
#ifdef CONFIG_HAVE_PROC_CPU
|
|
|
|
static int __init proc_cpu_init(void)
|
|
|
|
{
|
|
|
|
struct proc_dir_entry *res;
|
|
|
|
|
|
|
|
res = proc_mkdir("cpu", NULL);
|
|
|
|
if (!res)
|
|
|
|
return -ENOMEM;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
fs_initcall(proc_cpu_init);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int c_show(struct seq_file *m, void *v)
|
|
|
|
{
|
|
|
|
seq_printf(m, "Processor\t: UniCore-II rev %d (%s)\n",
|
|
|
|
(int)(uc32_cpuid >> 16) & 15, elf_platform);
|
|
|
|
|
|
|
|
seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
|
|
|
|
loops_per_jiffy / (500000/HZ),
|
|
|
|
(loops_per_jiffy / (5000/HZ)) % 100);
|
|
|
|
|
|
|
|
/* dump out the processor features */
|
|
|
|
seq_puts(m, "Features\t: CMOV UC-F64");
|
|
|
|
|
|
|
|
seq_printf(m, "\nCPU implementer\t: 0x%02x\n", uc32_cpuid >> 24);
|
|
|
|
seq_printf(m, "CPU architecture: 2\n");
|
|
|
|
seq_printf(m, "CPU revision\t: %d\n", (uc32_cpuid >> 16) & 15);
|
|
|
|
|
|
|
|
seq_printf(m, "Cache type\t: write-back\n"
|
|
|
|
"Cache clean\t: cp0 c5 ops\n"
|
|
|
|
"Cache lockdown\t: not support\n"
|
|
|
|
"Cache format\t: Harvard\n");
|
|
|
|
|
|
|
|
seq_puts(m, "\n");
|
|
|
|
|
|
|
|
seq_printf(m, "Hardware\t: PKUnity v3\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *c_start(struct seq_file *m, loff_t *pos)
|
|
|
|
{
|
|
|
|
return *pos < 1 ? (void *)1 : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
|
|
|
|
{
|
|
|
|
++*pos;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void c_stop(struct seq_file *m, void *v)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct seq_operations cpuinfo_op = {
|
|
|
|
.start = c_start,
|
|
|
|
.next = c_next,
|
|
|
|
.stop = c_stop,
|
|
|
|
.show = c_show
|
|
|
|
};
|