2026-01-21 18:59:54 +08:00

1038 lines
25 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* linux/arch/sw/kernel/setup.c
*
* Copyright (C) 1995 Linus Torvalds
*/
/*
* Bootup setup stuff.
*/
#include <linux/screen_info.h>
#include <linux/delay.h>
#include <linux/kexec.h>
#include <linux/console.h>
#include <linux/memblock.h>
#include <linux/root_dev.h>
#include <linux/initrd.h>
#ifdef CONFIG_MAGIC_SYSRQ
#include <linux/sysrq.h>
#include <linux/reboot.h>
#endif
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#endif
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <linux/genalloc.h>
#include <linux/acpi.h>
#include <asm/sw64_init.h>
#include <asm/efi.h>
#include <asm/kvm_cma.h>
#include "proto.h"
#include "pci_impl.h"
#undef DEBUG_DISCONTIG
#ifdef DEBUG_DISCONTIG
#define DBGDCONT(args...) pr_debug(args)
#else
#define DBGDCONT(args...)
#endif
DEFINE_PER_CPU(unsigned long, hard_node_id) = { 0 };
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
struct cma *sw64_kvm_cma;
EXPORT_SYMBOL(sw64_kvm_cma);
static phys_addr_t kvm_mem_size;
static phys_addr_t kvm_mem_base;
struct gen_pool *sw64_kvm_pool;
EXPORT_SYMBOL(sw64_kvm_pool);
#endif
static inline int phys_addr_valid(unsigned long addr)
{
/*
* At this point memory probe has not been done such that max_pfn
* and other physical address variables cannnot be used, so let's
* roughly judge physical address based on arch specific bit.
*/
return !(addr >> (cpu_desc.pa_bits - 1));
}
extern struct atomic_notifier_head panic_notifier_list;
static int sw64_panic_event(struct notifier_block *, unsigned long, void *);
static struct notifier_block sw64_panic_block = {
sw64_panic_event,
NULL,
INT_MAX /* try to do it first */
};
/* the value is IOR: CORE_ONLIE*/
cpumask_t core_start = CPU_MASK_NONE;
static struct resource data_resource = {
.name = "Kernel data",
.start = 0,
.end = 0,
.flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM
};
static struct resource code_resource = {
.name = "Kernel code",
.start = 0,
.end = 0,
.flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM
};
static struct resource bss_resource = {
.name = "Kernel bss",
.start = 0,
.end = 0,
.flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM
};
/* A collection of per-processor data. */
struct cpuinfo_sw64 cpu_data[NR_CPUS];
EXPORT_SYMBOL(cpu_data);
DEFINE_STATIC_KEY_TRUE(run_mode_host_key);
DEFINE_STATIC_KEY_FALSE(run_mode_guest_key);
DEFINE_STATIC_KEY_FALSE(run_mode_emul_key);
struct cpu_desc_t cpu_desc;
struct socket_desc_t socket_desc[MAX_NUMSOCKETS];
int memmap_nr;
struct memmap_entry memmap_map[MAX_NUMMEMMAPS];
bool memblock_initialized;
cpumask_t cpu_offline = CPU_MASK_NONE;
static char command_line[COMMAND_LINE_SIZE] __initdata;
#ifdef CONFIG_CMDLINE_BOOL
static char builtin_cmdline[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
#endif
/* boot_params */
struct boot_params *sunway_boot_params = (struct boot_params *) (PARAM + 0x100);
/*
* The format of "screen_info" is strange, and due to early
* i386-setup code. This is just enough to make the console
* code think we're on a VGA color display.
*/
struct screen_info screen_info = {
.orig_x = 0,
.orig_y = 25,
.orig_video_cols = 80,
.orig_video_lines = 25,
.orig_video_isVGA = 1,
.orig_video_points = 16
};
EXPORT_SYMBOL(screen_info);
#ifdef CONFIG_KEXEC
void *kexec_control_page;
#define KTEXT_MAX KERNEL_IMAGE_SIZE
static void __init kexec_control_page_init(void)
{
phys_addr_t addr;
addr = memblock_phys_alloc_range(KEXEC_CONTROL_PAGE_SIZE, PAGE_SIZE,
0, KTEXT_MAX);
kexec_control_page = (void *)(__START_KERNEL_map + addr);
}
/*
* reserve_crashkernel() - reserves memory are for crash kernel
*
* This function reserves memory area given in "crashkernel=" kernel command
* line parameter. The memory reserved is used by a dump capture kernel when
* primary kernel is crashing.
*/
static void __init reserve_crashkernel(void)
{
unsigned long long crash_size, crash_base;
int ret;
ret = parse_crashkernel(boot_command_line, mem_desc.size,
&crash_size, &crash_base);
if (ret || !crash_size)
return;
if (!memblock_is_region_memory(crash_base, crash_size))
memblock_add(crash_base, crash_size);
ret = memblock_reserve(crash_base, crash_size);
if (ret < 0) {
pr_warn("crashkernel reservation failed - memory is in use [mem %#018llx-%#018llx]\n",
crash_base, crash_base + crash_size - 1);
return;
}
pr_info("Reserving %ldMB of memory at %ldMB for crashkernel (System RAM: %ldMB)\n",
(unsigned long)(crash_size >> 20),
(unsigned long)(crash_base >> 20),
(unsigned long)(mem_desc.size >> 20));
ret = add_memmap_region(crash_base, crash_size, memmap_crashkernel);
if (ret)
pr_warn("Add crash kernel area [mem %#018llx-%#018llx] to memmap region failed.\n",
crash_base, crash_base + crash_size - 1);
if (crash_base >= KERNEL_IMAGE_SIZE)
pr_warn("Crash base should be less than %#x\n", KERNEL_IMAGE_SIZE);
crashk_res.start = crash_base;
crashk_res.end = crash_base + crash_size - 1;
insert_resource(&iomem_resource, &crashk_res);
}
#else /* !defined(CONFIG_KEXEC) */
static void __init reserve_crashkernel(void) {}
static void __init kexec_control_page_init(void) {}
#endif /* !defined(CONFIG_KEXEC) */
/*
* I/O resources inherited from PeeCees. Except for perhaps the
* turbochannel SWs, everyone has these on some sort of SuperIO chip.
*
* ??? If this becomes less standard, move the struct out into the
* machine vector.
*/
static void __init
reserve_std_resources(void)
{
static struct resource standard_io_resources[] = {
{ .name = "rtc", .start = -1, .end = -1 },
{ .name = "dma1", .start = 0x00, .end = 0x1f },
{ .name = "pic1", .start = 0x20, .end = 0x3f },
{ .name = "timer", .start = 0x40, .end = 0x5f },
{ .name = "keyboard", .start = 0x60, .end = 0x6f },
{ .name = "dma page reg", .start = 0x80, .end = 0x8f },
{ .name = "pic2", .start = 0xa0, .end = 0xbf },
{ .name = "dma2", .start = 0xc0, .end = 0xdf },
};
struct resource *io = &ioport_resource;
size_t i;
if (hose_head) {
struct pci_controller *hose;
for (hose = hose_head; hose; hose = hose->next)
if (hose->index == 0) {
io = hose->io_space;
break;
}
}
/* Fix up for the Jensen's queer RTC placement. */
standard_io_resources[0].start = RTC_PORT(0);
standard_io_resources[0].end = RTC_PORT(0) + 0x10;
for (i = 0; i < ARRAY_SIZE(standard_io_resources); ++i)
request_resource(io, standard_io_resources+i);
}
static int __init parse_memmap_one(char *p)
{
char *oldp;
u64 start_at, mem_size;
int ret;
if (!p)
return -EINVAL;
if (!strncmp(p, "exactmap", 8)) {
pr_err("\"memmap=exactmap\" not valid on sw64\n");
return 0;
}
oldp = p;
mem_size = memparse(p, &p);
if (p == oldp)
return -EINVAL;
if (*p == '@') {
pr_err("\"memmap=nn@ss\" invalid on sw64\n");
} else if (*p == '#') {
pr_err("\"memmap=nn#ss\" (force ACPI data) invalid on sw64\n");
} else if (*p == '$') {
start_at = memparse(p + 1, &p);
ret = add_memmap_region(start_at, mem_size, memmap_reserved);
if (ret)
return ret;
} else {
return -EINVAL;
}
return *p == '\0' ? 0 : -EINVAL;
}
static int __init setup_memmap(char *str)
{
while (str) {
char *k = strchr(str, ',');
if (k)
*k++ = 0;
parse_memmap_one(str);
str = k;
}
return 0;
}
early_param("memmap", setup_memmap);
static int __init setup_cpuoffline(char *p)
{
cpulist_parse(p, &cpu_offline);
cpumask_clear_cpu(0, &cpu_offline);
return 0;
}
early_param("cpuoffline", setup_cpuoffline);
#ifdef CONFIG_BLK_DEV_INITRD
static void * __init move_initrd(unsigned long mem_limit)
{
void *start;
unsigned long size;
size = initrd_end - initrd_start;
start = memblock_alloc_from(PAGE_ALIGN(size), PAGE_SIZE, 0);
if (!start || __pa(start) + size > mem_limit) {
initrd_start = initrd_end = 0;
return NULL;
}
memmove(start, (void *)initrd_start, size);
initrd_start = (unsigned long)start;
initrd_end = initrd_start + size;
pr_info("initrd moved to 0x%px\n", start);
return start;
}
#else
static void * __init move_initrd(unsigned long mem_limit)
{
return NULL;
}
#endif
static int __init memmap_range_valid(phys_addr_t base, phys_addr_t size)
{
if ((base + size) <= memblock_end_of_DRAM())
return true;
else
return false;
}
void __init process_memmap(void)
{
static int i; // Make it static so we won't start over again every time.
int ret;
phys_addr_t base, size;
unsigned long dma_end __maybe_unused = virt_to_phys((void *)MAX_DMA_ADDRESS);
if (!memblock_initialized)
return;
for (; i < memmap_nr; i++) {
base = memmap_map[i].addr;
size = memmap_map[i].size;
switch (memmap_map[i].type) {
case memmap_reserved:
if (!memmap_range_valid(base, size)) {
pr_err("reserved memmap region [mem %#018llx-%#018llx] extends beyond end of memory (%#018llx)\n",
base, base + size - 1, memblock_end_of_DRAM());
} else {
pr_info("reserved memmap region [mem %#018llx-%#018llx]\n",
base, base + size - 1);
ret = memblock_mark_nomap(base, size);
if (ret)
pr_err("reserve memmap region [mem %#018llx-%#018llx] failed\n",
base, base + size - 1);
else if (IS_ENABLED(CONFIG_ZONE_DMA32) && (base < dma_end))
pr_warn("memmap region [mem %#018llx-%#018llx] overlapped with DMA32 region\n",
base, base + size - 1);
}
break;
case memmap_pci:
if (!memmap_range_valid(base, size)) {
pr_info("pci memmap region [mem %#018llx-%#018llx] extends beyond end of memory (%#018llx)\n",
base, base + size - 1, memblock_end_of_DRAM());
} else {
pr_info("pci memmap region [mem %#018llx-%#018llx]\n",
base, base + size - 1);
ret = memblock_mark_nomap(base, size);
if (ret)
pr_err("reserve memmap region [mem %#018llx-%#018llx] failed\n",
base, base + size - 1);
}
break;
case memmap_initrd:
if (!memmap_range_valid(base, size)) {
phys_addr_t old_base = base;
base = (unsigned long) move_initrd(memblock_end_of_DRAM());
if (!base) {
pr_err("initrd memmap region [mem %#018llx-%#018llx] extends beyond end of memory (%#018llx)\n",
old_base, old_base + size - 1, memblock_end_of_DRAM());
} else {
memmap_map[i].addr = base;
pr_info("initrd memmap region [mem %#018llx-%#018llx]\n",
base, base + size - 1);
ret = memblock_reserve(base, size);
if (ret)
pr_err("reserve memmap region [mem %#018llx-%#018llx] failed\n",
base, base + size - 1);
}
} else {
pr_info("initrd memmap region [mem %#018llx-%#018llx]\n", base, base + size - 1);
ret = memblock_reserve(base, size);
if (ret)
pr_err("reserve memmap region [mem %#018llx-%#018llx] failed\n",
base, base + size - 1);
}
break;
case memmap_kvm:
case memmap_crashkernel:
/* kvm and crashkernel are handled elsewhere, skip */
break;
case memmap_acpi:
pr_err("ACPI memmap region is not supported.\n");
break;
case memmap_use:
pr_err("Force usage memmap region is not supported.\n");
break;
case memmap_protected:
pr_err("Protected memmap region is not supported.\n");
break;
default:
pr_err("Unknown type of memmap region.\n");
}
}
}
int __init add_memmap_region(u64 addr, u64 size, enum memmap_types type)
{
if (memmap_nr >= ARRAY_SIZE(memmap_map)) {
pr_err("Ooops! Too many entries in the memory map!\n");
return -EPERM;
}
if (addr + size <= addr) {
pr_warn("Trying to add an invalid memory region, skipped\n");
return -EINVAL;
}
memmap_map[memmap_nr].addr = addr;
memmap_map[memmap_nr].size = size;
memmap_map[memmap_nr].type = type;
memmap_nr++;
process_memmap();
return 0;
}
static struct resource* __init
insert_ram_resource(u64 start, u64 end, bool reserved)
{
struct resource *res =
kzalloc(sizeof(struct resource), GFP_ATOMIC);
if (!res)
return NULL;
if (reserved) {
res->name = "reserved";
res->flags = IORESOURCE_MEM;
} else {
res->name = "System RAM";
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
}
res->start = start;
res->end = end;
if (insert_resource(&iomem_resource, res)) {
kfree(res);
return NULL;
}
return res;
}
static int __init request_standard_resources(void)
{
struct memblock_region *mblk;
extern char _text[], _etext[];
extern char _sdata[], _edata[];
extern char __bss_start[], __bss_stop[];
for_each_mem_region(mblk) {
if (!memblock_is_nomap(mblk))
insert_ram_resource(mblk->base,
mblk->base + mblk->size - 1, 0);
else
insert_ram_resource(mblk->base,
mblk->base + mblk->size - 1, 1);
}
code_resource.start = __pa_symbol(_text);
code_resource.end = __pa_symbol(_etext)-1;
data_resource.start = __pa_symbol(_sdata);
data_resource.end = __pa_symbol(_edata)-1;
bss_resource.start = __pa_symbol(__bss_start);
bss_resource.end = __pa_symbol(__bss_stop)-1;
insert_resource(&iomem_resource, &code_resource);
insert_resource(&iomem_resource, &data_resource);
insert_resource(&iomem_resource, &bss_resource);
return 0;
}
subsys_initcall(request_standard_resources);
#ifdef CONFIG_NUMA
extern void cpu_set_node(void);
#endif
static void __init show_socket_mem_layout(void)
{
int i;
phys_addr_t base, size, end;
base = 0;
pr_info("Socket memory layout:\n");
for (i = 0; i < MAX_NUMSOCKETS; i++) {
if (socket_desc[i].is_online) {
size = socket_desc[i].socket_mem;
end = base + size - 1;
pr_info("Socket %d: [mem %#018llx-%#018llx], size %llu\n",
i, base, end, size);
base = end + 1;
}
}
pr_info("Reserved memory size for Socket 0: %#lx\n", NODE0_START);
}
int page_is_ram(unsigned long pfn)
{
pfn <<= PAGE_SHIFT;
return pfn >= mem_desc.base && pfn < (mem_desc.base + mem_desc.size);
}
static int __init topology_init(void)
{
int i;
#ifdef CONFIG_NUMA
for_each_online_node(i)
register_one_node(i);
#endif
for_each_possible_cpu(i) {
struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
#ifdef CONFIG_HOTPLUG_CPU
if (i != 0)
p->hotpluggable = 1;
#endif
register_cpu(p, i);
}
return 0;
}
subsys_initcall(topology_init);
static void __init setup_machine_fdt(void)
{
#ifdef CONFIG_USE_OF
void *dt_virt;
const char *name;
unsigned long phys_addr;
/* Give a chance to select kernel builtin DTB firstly */
if (IS_ENABLED(CONFIG_SW64_BUILTIN_DTB))
dt_virt = (void *)__dtb_start;
else
dt_virt = (void *)sunway_boot_params->dtb_start;
phys_addr = __phys_addr((unsigned long)dt_virt);
if (!phys_addr_valid(phys_addr) ||
!early_init_dt_scan(dt_virt)) {
pr_crit("\n"
"Error: invalid device tree blob at virtual address %px\n"
"The dtb must be 8-byte aligned and must not exceed 2 MB in size\n"
"\nPlease check your bootloader.",
dt_virt);
while (true)
cpu_relax();
}
name = of_flat_dt_get_machine_name();
if (!name)
return;
pr_info("Machine model: %s\n", name);
#else
pr_info("Kernel disable device tree support.\n");
return;
#endif
}
void __init device_tree_init(void)
{
unflatten_and_copy_device_tree();
sunway_boot_params->dtb_start = (__u64)initial_boot_params;
}
static void __init setup_cpu_info(void)
{
int i;
struct cache_desc *c;
unsigned long val;
val = cpuid(GET_TABLE_ENTRY, 0);
cpu_desc.model = CPUID_MODEL(val);
cpu_desc.family = CPUID_FAMILY(val);
cpu_desc.chip_var = CPUID_CHIP_VAR(val);
cpu_desc.arch_var = CPUID_ARCH_VAR(val);
cpu_desc.arch_rev = CPUID_ARCH_REV(val);
cpu_desc.pa_bits = CPUID_PA_BITS(val);
cpu_desc.va_bits = CPUID_VA_BITS(val);
if (*(unsigned long *)MMSIZE) {
static_branch_disable(&run_mode_host_key);
if (*(unsigned long *)MMSIZE & EMUL_FLAG) {
pr_info("run mode: emul\n");
static_branch_disable(&run_mode_guest_key);
static_branch_enable(&run_mode_emul_key);
} else {
pr_info("run mode: guest\n");
static_branch_enable(&run_mode_guest_key);
static_branch_disable(&run_mode_emul_key);
}
} else {
pr_info("run mode: host\n");
static_branch_enable(&run_mode_host_key);
static_branch_disable(&run_mode_guest_key);
static_branch_disable(&run_mode_emul_key);
}
for (i = 0; i < VENDOR_ID_MAX; i++) {
val = cpuid(GET_VENDOR_ID, i);
memcpy(cpu_desc.vendor_id + (i * 8), &val, 8);
}
for (i = 0; i < MODEL_MAX; i++) {
val = cpuid(GET_MODEL, i);
memcpy(cpu_desc.model_id + (i * 8), &val, 8);
}
cpu_desc.frequency = cpuid(GET_CPU_FREQ, 0) * 1000UL * 1000UL;
for (i = 0; i < NR_CPUS; i++) {
c = &(cpu_data[i].icache);
val = cpuid(GET_CACHE_INFO, L1_ICACHE);
c->size = CACHE_SIZE(val);
c->linesz = 1 << (CACHE_LINE_BITS(val));
c->sets = 1 << (CACHE_INDEX_BITS(val));
c->ways = c->size / c->sets / c->linesz;
c = &(cpu_data[i].dcache);
val = cpuid(GET_CACHE_INFO, L1_DCACHE);
c->size = CACHE_SIZE(val);
c->linesz = 1 << (CACHE_LINE_BITS(val));
c->sets = 1 << (CACHE_INDEX_BITS(val));
c->ways = c->size / c->sets / c->linesz;
c = &(cpu_data[i].scache);
val = cpuid(GET_CACHE_INFO, L2_CACHE);
c->size = CACHE_SIZE(val);
c->linesz = 1 << (CACHE_LINE_BITS(val));
c->sets = 1 << (CACHE_INDEX_BITS(val));
c->ways = c->size / c->sets / c->linesz;
c = &(cpu_data[i].tcache);
val = cpuid(GET_CACHE_INFO, L3_CACHE);
c->size = CACHE_SIZE(val);
c->linesz = 1 << (CACHE_LINE_BITS(val));
c->sets = 1 << (CACHE_INDEX_BITS(val));
c->ways = c->size / c->sets / c->linesz;
}
}
static void __init setup_socket_info(void)
{
int i;
int numsockets = sw64_chip->get_cpu_num();
memset(socket_desc, 0, MAX_NUMSOCKETS * sizeof(struct socket_desc_t));
for (i = 0; i < numsockets; i++) {
socket_desc[i].is_online = 1;
if (sw64_chip_init->early_init.get_node_mem)
socket_desc[i].socket_mem = sw64_chip_init->early_init.get_node_mem(i);
}
}
#ifdef CONFIG_BLK_DEV_INITRD
static void __init reserve_mem_for_initrd(void)
{
int ret;
initrd_start = sunway_boot_params->initrd_start;
if (initrd_start) {
initrd_start = __pa(initrd_start) + PAGE_OFFSET;
initrd_end = initrd_start + sunway_boot_params->initrd_size;
pr_info("Initial ramdisk at: 0x%px (%llu bytes)\n",
(void *)initrd_start, sunway_boot_params->initrd_size);
ret = add_memmap_region(__pa(initrd_start), initrd_end - initrd_start, memmap_initrd);
if (ret)
pr_err("Add initrd area [mem %#018lx-%#018lx] to memmap region failed.\n",
__pa(initrd_start), __pa(initrd_end - 1));
}
}
#endif /* CONFIG_BLK_DEV_INITRD */
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
static int __init early_kvm_reserved_mem(char *p)
{
if (!p) {
pr_err("Config string not provided\n");
return -EINVAL;
}
kvm_mem_size = memparse(p, &p);
if (*p != '@')
return -EINVAL;
kvm_mem_base = memparse(p + 1, &p);
return 0;
}
early_param("kvm_mem", early_kvm_reserved_mem);
void __init sw64_kvm_reserve(void)
{
kvm_cma_declare_contiguous(kvm_mem_base, kvm_mem_size, 0,
PAGE_SIZE, 0, "sw64_kvm_cma", &sw64_kvm_cma);
}
#endif
void __init
setup_arch(char **cmdline_p)
{
jump_label_init();
setup_cpu_info();
sw64_chip->fixup();
sw64_chip_init->fixup();
setup_socket_info();
show_socket_mem_layout();
sw64_chip_init->early_init.setup_core_start(&core_start);
setup_sched_clock();
#ifdef CONFIG_GENERIC_SCHED_CLOCK
sw64_sched_clock_init();
#endif
setup_machine_fdt();
/* Register a call for panic conditions. */
atomic_notifier_chain_register(&panic_notifier_list,
&sw64_panic_block);
callback_init();
/* command line */
if (!sunway_boot_params->cmdline)
sunway_boot_params->cmdline = (unsigned long)COMMAND_LINE;
strlcpy(boot_command_line, (char *)sunway_boot_params->cmdline, COMMAND_LINE_SIZE);
#if IS_ENABLED(CONFIG_CMDLINE_BOOL)
#if IS_ENABLED(CONFIG_CMDLINE_OVERRIDE)
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
strlcpy((char *)sunway_boot_params->cmdline, boot_command_line, COMMAND_LINE_SIZE);
#else
if (builtin_cmdline[0]) {
/* append builtin to boot loader cmdline */
strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
}
#endif /* CMDLINE_EXTEND */
#endif
if (IS_ENABLED(CONFIG_SW64_CHIP3_ASIC_DEBUG) &&
IS_ENABLED(CONFIG_SW64_CHIP3)) {
unsigned long bmc, cpu_online, node;
bmc = *(unsigned long *)__va(0x800000);
pr_info("bmc = %ld\n", bmc);
cpu_online = sw64_chip->get_cpu_num();
for (node = 0; node < cpu_online; node++)
sw64_io_write(node, SI_FAULT_INT_EN, 0);
sprintf(boot_command_line, "root=/dev/sda2 ip=172.16.137.%ld::172.16.137.254:255.255.255.0::eth0:off", 180+bmc);
}
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
/*
* Process command-line arguments.
*/
parse_early_param();
/* Find our memory. */
mem_detect();
#ifdef CONFIG_PCI
reserve_mem_for_pci();
#endif
#ifdef CONFIG_BLK_DEV_INITRD
reserve_mem_for_initrd();
#endif
sw64_memblock_init();
/* Reserve large chunks of memory for use by CMA for KVM. */
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
sw64_kvm_reserve();
#endif
sw64_numa_init();
memblock_dump_all();
sparse_init();
zone_sizes_init();
paging_init();
kexec_control_page_init();
efi_init();
/* Parse the ACPI tables for possible boot-time configuration */
acpi_boot_table_init();
/*
* Initialize the machine. Usually has to do with setting up
* DMA windows and the like.
*/
sw64_init_arch();
reserve_crashkernel();
/* Reserve standard resources. */
reserve_std_resources();
/*
* Give us a default console. TGA users will see nothing until
* chr_dev_init is called, rather late in the boot sequence.
*/
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
#endif
/* Default root filesystem to sda2. */
ROOT_DEV = Root_SDA2;
/*
* Identify the flock of penguins.
*/
#ifdef CONFIG_SMP
setup_smp();
#endif
#ifdef CONFIG_NUMA
cpu_set_node();
#endif
if (acpi_disabled)
device_tree_init();
}
static int
show_cpuinfo(struct seq_file *f, void *slot)
{
int i;
unsigned long cpu_freq;
cpu_freq = get_cpu_freq() / 1000 / 1000;
for_each_online_cpu(i) {
/*
* glibc reads /proc/cpuinfo to determine the number of
* online processors, looking for lines beginning with
* "processor". Give glibc what it expects.
*/
seq_printf(f, "processor\t: %u\n"
"vendor_id\t: %s\n"
"cpu family\t: %d\n"
"model\t\t: %u\n"
"model name\t: %s CPU @ %lu.%lu%luGHz\n"
"cpu variation\t: %u\n"
"cpu revision\t: %u\n",
i, cpu_desc.vendor_id, cpu_desc.family,
cpu_desc.model, cpu_desc.model_id,
cpu_freq / 1000, (cpu_freq % 1000) / 100,
(cpu_freq % 100) / 10,
cpu_desc.arch_var, cpu_desc.arch_rev);
seq_printf(f, "cpu MHz\t\t: %lu.00\n"
"cache size\t: %u KB\n"
"physical id\t: %d\n"
"bogomips\t: %lu.%02lu\n",
cpu_freq, cpu_data[i].tcache.size >> 10,
cpu_to_rcid(i),
loops_per_jiffy / (500000/HZ),
(loops_per_jiffy / (5000/HZ)) % 100);
seq_printf(f, "flags\t\t: fpu simd vpn upn cpuid\n");
seq_printf(f, "page size\t: %d\n", 8192);
seq_printf(f, "cache_alignment\t: %d\n", cpu_data[i].tcache.linesz);
seq_printf(f, "address sizes\t: %u bits physical, %u bits virtual\n\n",
cpu_desc.pa_bits, cpu_desc.va_bits);
}
return 0;
}
/*
* We show only CPU #0 info.
*/
static void *
c_start(struct seq_file *f, loff_t *pos)
{
return *pos < 1 ? (void *)1 : NULL;
}
static void *
c_next(struct seq_file *f, void *v, loff_t *pos)
{
(*pos)++;
return NULL;
}
static void
c_stop(struct seq_file *f, void *v)
{
}
const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
.show = show_cpuinfo,
};
static int
sw64_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
{
return NOTIFY_DONE;
}
static __init int add_pcspkr(void)
{
struct platform_device *pd;
int ret;
pd = platform_device_alloc("pcspkr", -1);
if (!pd)
return -ENOMEM;
ret = platform_device_add(pd);
if (ret)
platform_device_put(pd);
return ret;
}
device_initcall(add_pcspkr);
#ifdef CONFIG_DEBUG_FS
struct dentry *sw64_debugfs_dir;
static int __init debugfs_sw64(void)
{
struct dentry *d;
d = debugfs_create_dir("sw_64", NULL);
if (!d)
return -ENOMEM;
sw64_debugfs_dir = d;
return 0;
}
arch_initcall(debugfs_sw64);
#endif
#ifdef CONFIG_OF
static int __init sw64_of_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
return 0;
}
core_initcall(sw64_of_init);
#endif
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
static int __init sw64_kvm_pool_init(void)
{
int status = 0;
unsigned long kvm_pool_virt;
struct page *base_page, *end_page, *p;
if (!sw64_kvm_cma)
goto out;
kvm_pool_virt = (unsigned long)kvm_mem_base;
sw64_kvm_pool = gen_pool_create(PAGE_SHIFT, -1);
if (!sw64_kvm_pool)
goto out;
status = gen_pool_add_virt(sw64_kvm_pool, kvm_pool_virt, kvm_mem_base,
kvm_mem_size, -1);
if (status < 0) {
pr_err("failed to add memory chunks to sw64 kvm pool\n");
gen_pool_destroy(sw64_kvm_pool);
sw64_kvm_pool = NULL;
goto out;
}
gen_pool_set_algo(sw64_kvm_pool, gen_pool_best_fit, NULL);
base_page = pfn_to_page(kvm_mem_base >> PAGE_SHIFT);
end_page = pfn_to_page((kvm_mem_base + kvm_mem_size - 1) >> PAGE_SHIFT);
p = base_page;
while (page_ref_count(p) == 0 &&
(unsigned long)p <= (unsigned long)end_page) {
set_page_count(p, 1);
page_mapcount_reset(p);
SetPageReserved(p);
p++;
}
return status;
out:
return -ENOMEM;
}
core_initcall_sync(sw64_kvm_pool_init);
#endif