/* * 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) 2011 by Kevin Cernekee (cernekee@gmail.com) * * SMP support for BMIPS
*/
/* these may be configured by the platform code */ int bmips_smp_enabled = 1; int bmips_cpu_offset;
cpumask_t bmips_booted_mask; unsignedlong bmips_tp1_irqs = IE_IRQ1;
staticvoid __init bmips_smp_setup(void)
{ int i, cpu = 1, boot_cpu = 0; int cpu_hw_intr;
switch (current_cpu_type()) { case CPU_BMIPS4350: case CPU_BMIPS4380: /* arbitration priority */
clear_c0_brcm_cmt_ctrl(0x30);
/* NBK and weak order flags */
set_c0_brcm_config_0(0x30000);
/* Find out if we are running on TP0 or TP1 */
boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
/* * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other * thread * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output
*/ if (boot_cpu == 0)
cpu_hw_intr = 0x02; else
cpu_hw_intr = 0x1d;
if (cpumask_test_cpu(cpu, &bmips_booted_mask)) { /* kseg1 might not exist if this CPU enabled XKS01 */
bmips_set_reset_vec(cpu, RESET_FROM_KSEG0);
switch (current_cpu_type()) { case CPU_BMIPS4350: case CPU_BMIPS4380:
bmips43xx_send_ipi_single(cpu, 0); break; case CPU_BMIPS5000:
bmips5000_send_ipi_single(cpu, 0); break;
}
} else {
bmips_set_reset_vec(cpu, RESET_FROM_KSEG1);
switch (current_cpu_type()) { case CPU_BMIPS4350: case CPU_BMIPS4380: /* Reset slave TP1 if booting from TP0 */ if (cpu_logical_map(cpu) == 1)
set_c0_brcm_cmt_ctrl(0x01); break; case CPU_BMIPS5000:
write_c0_brcm_action(ACTION_BOOT_THREAD(cpu)); break;
}
cpumask_set_cpu(cpu, &bmips_booted_mask);
}
return 0;
}
/* * Early setup - runs on secondary CPU after cache probe
*/ staticvoid bmips_init_secondary(void)
{
bmips_cpu_setup();
switch (current_cpu_type()) { case CPU_BMIPS4350: case CPU_BMIPS4380:
clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0); break; case CPU_BMIPS5000:
write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0));
cpu_set_core(¤t_cpu_data, (read_c0_brcm_config() >> 25) & 3); break;
}
}
/* * Late setup - runs on secondary CPU before entering the idle loop
*/ staticvoid bmips_smp_finish(void)
{
pr_info("SMP: CPU%d is running\n", smp_processor_id());
/* make sure there won't be a timer interrupt for a little while */
write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
/* * BMIPS5000 raceless IPIs * * Each CPU has two inbound SW IRQs which are independent of all other CPUs. * IPI0 is used for SMP_RESCHEDULE_YOURSELF * IPI1 is used for SMP_CALL_FUNCTION
*/
/* * BMIPS43xx racey IPIs * * We use one inbound SW IRQ for each CPU. * * A spinlock must be held in order to keep CPUx from accidentally clearing * an incoming IPI when it writes CP0 CAUSE to raise an IPI on CPUy. The * same spinlock is used to protect the action masks.
*/
/*********************************************************************** * BMIPS vector relocation * This is primarily used for SMP boot, but it is applicable to some * UP BMIPS systems as well.
***********************************************************************/
switch (current_cpu_type()) { case CPU_BMIPS4350: /* * BMIPS4350 cannot relocate the normal vectors, but it * can relocate the BEV=1 vectors. So CPU1 starts up at * the relocated BEV=1, IV=0 general exception vector @ * 0xa000_0380. * * set_uncached_handler() is used here because: * - CPU1 will run this from uncached space * - None of the cacheflush functions are set up yet
*/
set_uncached_handler(BMIPS_WARM_RESTART_VEC - CKSEG0,
&bmips_smp_int_vec, 0x80);
__sync(); return; case CPU_BMIPS3300: case CPU_BMIPS4380: /* * 0x8000_0000: reset/NMI (initially in kseg1) * 0x8000_0400: normal vectors
*/
new_ebase = 0x80000400;
bmips_set_reset_vec(0, RESET_FROM_KSEG0); break; case CPU_BMIPS5000: /* * 0x8000_0000: reset/NMI (initially in kseg1) * 0x8000_1000: normal vectors
*/
new_ebase = 0x80001000;
bmips_set_reset_vec(0, RESET_FROM_KSEG0);
write_c0_ebase(new_ebase); break; default: return;
}
asmlinkage void __weak plat_wired_tlb_setup(void)
{ /* * Called when starting/restarting a secondary CPU. * Kernel stacks and other important data might only be accessible * once the wired entries are present.
*/
}
/* Flush stale data out of the readahead cache */
cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG);
__raw_writel(cfg | 0x100, cbr + BMIPS_RAC_CONFIG);
__raw_readl(cbr + BMIPS_RAC_CONFIG); break;
case CPU_BMIPS4380: /* CBG workaround for early BMIPS4380 CPUs */ switch (read_c0_prid()) { case 0x2a040: case 0x2a042: case 0x2a044: case 0x2a060:
cfg = __raw_readl(cbr + BMIPS_L2_CONFIG);
__raw_writel(cfg & ~0x07000000, cbr + BMIPS_L2_CONFIG);
__raw_readl(cbr + BMIPS_L2_CONFIG);
}
/* clear BHTD to enable branch history table */
clear_c0_brcm_config_0(BIT(21));
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.