/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Copyright (C) 2004 Mips Technologies, Inc * Copyright (C) 2008 Kevin D. Kissell * * Lantiq platform specific hooks for SMP operation */ #include #include #include #include #include #include #include #ifdef CONFIG_AVM_ENHANCED #include #include #endif /* VPE/SMP Prototype implements platform interfaces directly */ /* * Cause the specified action to be performed on a targeted "CPU" */ static void lsmtc_send_ipi_single(int cpu, unsigned int action) { /* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */ smtc_send_ipi(cpu, LINUX_SMP_IPI, action); } static void lsmtc_send_ipi_mask(const struct cpumask *mask, unsigned int action) { unsigned int i; for_each_cpu(i, mask) lsmtc_send_ipi_single(i, action); } /* * Post-config but pre-boot cleanup entry point */ static void __cpuinit lsmtc_init_secondary(void) { struct cpuinfo_mips *c = ¤t_cpu_data; int myvpe; #ifdef CONFIG_AVM_ENHANCED init_dsp(); /* initialize DSP register cpu1 */ write_c0_errorepc(0); #endif c->core = (read_c0_ebase() >> 1) & 0xff; /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */ myvpe = read_c0_tcbind() & TCBIND_CURVPE; if (myvpe != 0) { /* Ideally, this should be done only once per VPE, but... */ clear_c0_status(ST0_IM); set_c0_status((0x100 << cp0_compare_irq) | (0x100 << MIPS_CPU_IPI_IRQ)); if (cp0_perfcount_irq >= 0) set_c0_status(0x100 << cp0_perfcount_irq); } smtc_init_secondary(); } /* * Platform "CPU" startup hook */ static void __cpuinit lsmtc_boot_secondary(int cpu, struct task_struct *idle) { smtc_boot_secondary(cpu, idle); } /* * SMP initialization finalization entry point */ static void __cpuinit lsmtc_smp_finish(void) { smtc_smp_finish(); } /* * Hook for after all CPUs are online */ static void lsmtc_cpus_done(void) { #ifdef CONFIG_AVM_ENHANCED #if defined(CONFIG_LANTIQ) if(NR_CPUS <= LANTIQ_YIELD_TC1) { #if LANTIQ_YIELD_MASK_TC1 > 0 yield_context_init_on(1, LANTIQ_YIELD_TC1, LANTIQ_YIELD_MASK_TC1); #endif #if LANTIQ_YIELD_MASK_TC2 > 0 yield_context_init_on(0, LANTIQ_YIELD_TC2, LANTIQ_YIELD_MASK_TC2); #endif } #endif/*--- #if defined(CONFIG_LANTIQ) ---*/ #endif/*--- #ifdef CONFIG_AVM_ENHANCED ---*/ } /* * Platform SMP pre-initialization * * As noted above, we can assume a single CPU for now * but it may be multithreaded. */ static void __init lsmtc_smp_setup(void) { /* * we won't get the definitive value until * we've run smtc_prepare_cpus later, but * we would appear to need an upper bound now. */ printk(KERN_ERR"[%u]%s tcstatus=%lx\n", raw_smp_processor_id(), __func__, read_tc_c0_tcstatus()); smp_num_siblings = smtc_build_cpu_map(0); } static void __init lsmtc_prepare_cpus(unsigned int max_cpus) { smtc_prepare_cpus(max_cpus); } struct plat_smp_ops lsmtc_smp_ops = { .send_ipi_single = lsmtc_send_ipi_single, .send_ipi_mask = lsmtc_send_ipi_mask, .init_secondary = lsmtc_init_secondary, .smp_finish = lsmtc_smp_finish, .cpus_done = lsmtc_cpus_done, .boot_secondary = lsmtc_boot_secondary, .smp_setup = lsmtc_smp_setup, .prepare_cpus = lsmtc_prepare_cpus, };