/* * 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) 2004-2008, 2009, 2010 Cavium Networks
*/ #include <linux/cpu.h> #include <linux/delay.h> #include <linux/smp.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> #include <linux/sched.h> #include <linux/sched/hotplug.h> #include <linux/sched/task_stack.h> #include <linux/init.h> #include <linux/export.h> #include <linux/kexec.h>
/* * Cause the function described by call_data to be executed on the passed * cpu. When the function has finished, increment the finished field of * call_data.
*/ void octeon_send_ipi_single(int cpu, unsignedint action)
{ int coreid = cpu_logical_map(cpu); /* pr_info("SMP: Mailbox send cpu=%d, coreid=%d, action=%u\n", cpu, coreid, action);
*/
cvmx_write_csr(CVMX_CIU_MBOX_SETX(coreid), action);
}
labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER); if (labi->labi_signature != LABI_SIGNATURE) {
pr_info("The bootloader on this board does not support HOTPLUG_CPU."); return;
}
/* The present CPUs are initially just the boot cpu (CPU 0). */ for (id = 0; id < NR_CPUS; id++) {
set_cpu_possible(id, id == 0);
set_cpu_present(id, id == 0);
}
/* The present CPUs get the lowest CPU numbers. */
cpus = 1; for (id = 0; id < NR_CPUS; id++) { if ((id != coreid) && cvmx_coremask_is_core_set(&sysinfo->core_mask, id)) {
set_cpu_possible(cpus, true);
set_cpu_present(cpus, true);
__cpu_number_map[id] = cpus;
__cpu_logical_map[cpus] = id;
cpus++;
}
}
#ifdef CONFIG_HOTPLUG_CPU /* * The possible CPUs are all those present on the chip. We * will assign CPU numbers for possible cores as well. Cores * are always consecutively numberd from 0.
*/ for (id = 0; setup_max_cpus && octeon_bootloader_entry_addr &&
id < num_cores && id < NR_CPUS; id++) { if (!(core_mask & (1 << id))) {
set_cpu_possible(cpus, true);
__cpu_number_map[id] = cpus;
__cpu_logical_map[cpus] = id;
cpus++;
}
} #endif
octeon_smp_hotplug_setup();
}
#ifdef CONFIG_RELOCATABLE int plat_post_relocation(long offset)
{ unsignedlong entry = (unsignedlong)kernel_entry;
count = 10000; while (octeon_processor_sp && count) { /* Waiting for processor to get the SP and GP */
udelay(1);
count--;
} if (count == 0) {
pr_err("Secondary boot timeout\n"); return -ETIMEDOUT;
}
return 0;
}
/* * After we've done initial boot, this function is called to allow the * board code to clean up state, if needed
*/ staticvoid octeon_init_secondary(void)
{ unsignedint sr;
sr = set_c0_status(ST0_BEV);
write_c0_ebase((u32)ebase);
write_c0_status(sr);
octeon_check_cpu_bist();
octeon_init_cvmcount();
octeon_irq_setup_secondary();
}
/* * Callout to firmware before smp_init
*/ staticvoid __init octeon_prepare_cpus(unsignedint max_cpus)
{ /* * Only the low order mailbox bits are used for IPIs, leave * the other bits alone.
*/
cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffff); if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt,
IRQF_PERCPU | IRQF_NO_THREAD, "SMP-IPI",
mailbox_interrupt)) {
panic("Cannot request_irq(OCTEON_IRQ_MBOX0)");
}
}
/* * Last chance for the board code to finish SMP initialization before * the CPU is "online".
*/ staticvoid octeon_smp_finish(void)
{
octeon_user_io_init();
/* to generate the first CPU timer interrupt */
write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
local_irq_enable();
}
#ifdef CONFIG_HOTPLUG_CPU
/* State of each CPU. */ static DEFINE_PER_CPU(int, cpu_state);
staticint octeon_cpu_disable(void)
{ unsignedint cpu = smp_processor_id();
if (!octeon_bootloader_entry_addr) return -ENOTSUPP;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.