linux/arch/mips/kernel/smp-mt.c
<<
>>
Prefs
   1/*
   2 *  This program is free software; you can distribute it and/or modify it
   3 *  under the terms of the GNU General Public License (Version 2) as
   4 *  published by the Free Software Foundation.
   5 *
   6 *  This program is distributed in the hope it will be useful, but WITHOUT
   7 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   8 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   9 *  for more details.
  10 *
  11 *  You should have received a copy of the GNU General Public License along
  12 *  with this program; if not, write to the Free Software Foundation, Inc.,
  13 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  14 *
  15 * Copyright (C) 2004, 05, 06 MIPS Technologies, Inc.
  16 *    Elizabeth Clarke (beth@mips.com)
  17 *    Ralf Baechle (ralf@linux-mips.org)
  18 * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
  19 */
  20#include <linux/kernel.h>
  21#include <linux/sched.h>
  22#include <linux/cpumask.h>
  23#include <linux/interrupt.h>
  24#include <linux/irqchip/mips-gic.h>
  25#include <linux/compiler.h>
  26#include <linux/sched/task_stack.h>
  27#include <linux/smp.h>
  28
  29#include <linux/atomic.h>
  30#include <asm/cacheflush.h>
  31#include <asm/cpu.h>
  32#include <asm/processor.h>
  33#include <asm/hardirq.h>
  34#include <asm/mmu_context.h>
  35#include <asm/time.h>
  36#include <asm/mipsregs.h>
  37#include <asm/mipsmtregs.h>
  38#include <asm/mips_mt.h>
  39
  40static void __init smvp_copy_vpe_config(void)
  41{
  42        write_vpe_c0_status(
  43                (read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
  44
  45        /* set config to be the same as vpe0, particularly kseg0 coherency alg */
  46        write_vpe_c0_config( read_c0_config());
  47
  48        /* make sure there are no software interrupts pending */
  49        write_vpe_c0_cause(0);
  50
  51        /* Propagate Config7 */
  52        write_vpe_c0_config7(read_c0_config7());
  53
  54        write_vpe_c0_count(read_c0_count());
  55}
  56
  57static unsigned int __init smvp_vpe_init(unsigned int tc, unsigned int mvpconf0,
  58        unsigned int ncpu)
  59{
  60        if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT))
  61                return ncpu;
  62
  63        /* Deactivate all but VPE 0 */
  64        if (tc != 0) {
  65                unsigned long tmp = read_vpe_c0_vpeconf0();
  66
  67                tmp &= ~VPECONF0_VPA;
  68
  69                /* master VPE */
  70                tmp |= VPECONF0_MVP;
  71                write_vpe_c0_vpeconf0(tmp);
  72
  73                /* Record this as available CPU */
  74                set_cpu_possible(tc, true);
  75                set_cpu_present(tc, true);
  76                __cpu_number_map[tc]    = ++ncpu;
  77                __cpu_logical_map[ncpu] = tc;
  78        }
  79
  80        /* Disable multi-threading with TC's */
  81        write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
  82
  83        if (tc != 0)
  84                smvp_copy_vpe_config();
  85
  86        cpu_data[ncpu].vpe_id = tc;
  87
  88        return ncpu;
  89}
  90
  91static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0)
  92{
  93        unsigned long tmp;
  94
  95        if (!tc)
  96                return;
  97
  98        /* bind a TC to each VPE, May as well put all excess TC's
  99           on the last VPE */
 100        if (tc >= (((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)+1))
 101                write_tc_c0_tcbind(read_tc_c0_tcbind() | ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT));
 102        else {
 103                write_tc_c0_tcbind(read_tc_c0_tcbind() | tc);
 104
 105                /* and set XTC */
 106                write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (tc << VPECONF0_XTC_SHIFT));
 107        }
 108
 109        tmp = read_tc_c0_tcstatus();
 110
 111        /* mark not allocated and not dynamically allocatable */
 112        tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
 113        tmp |= TCSTATUS_IXMT;           /* interrupt exempt */
 114        write_tc_c0_tcstatus(tmp);
 115
 116        write_tc_c0_tchalt(TCHALT_H);
 117}
 118
 119static void vsmp_init_secondary(void)
 120{
 121#ifdef CONFIG_MIPS_GIC
 122        /* This is Malta specific: IPI,performance and timer interrupts */
 123        if (gic_present)
 124                change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 |
 125                                         STATUSF_IP4 | STATUSF_IP5 |
 126                                         STATUSF_IP6 | STATUSF_IP7);
 127        else
 128#endif
 129                change_c0_status(ST0_IM, STATUSF_IP0 | STATUSF_IP1 |
 130                                         STATUSF_IP6 | STATUSF_IP7);
 131}
 132
 133static void vsmp_smp_finish(void)
 134{
 135        /* CDFIXME: remove this? */
 136        write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ));
 137
 138#ifdef CONFIG_MIPS_MT_FPAFF
 139        /* If we have an FPU, enroll ourselves in the FPU-full mask */
 140        if (cpu_has_fpu)
 141                cpumask_set_cpu(smp_processor_id(), &mt_fpu_cpumask);
 142#endif /* CONFIG_MIPS_MT_FPAFF */
 143
 144        local_irq_enable();
 145}
 146
 147/*
 148 * Setup the PC, SP, and GP of a secondary processor and start it
 149 * running!
 150 * smp_bootstrap is the place to resume from
 151 * __KSTK_TOS(idle) is apparently the stack pointer
 152 * (unsigned long)idle->thread_info the gp
 153 * assumes a 1:1 mapping of TC => VPE
 154 */
 155static void vsmp_boot_secondary(int cpu, struct task_struct *idle)
 156{
 157        struct thread_info *gp = task_thread_info(idle);
 158        dvpe();
 159        set_c0_mvpcontrol(MVPCONTROL_VPC);
 160
 161        settc(cpu);
 162
 163        /* restart */
 164        write_tc_c0_tcrestart((unsigned long)&smp_bootstrap);
 165
 166        /* enable the tc this vpe/cpu will be running */
 167        write_tc_c0_tcstatus((read_tc_c0_tcstatus() & ~TCSTATUS_IXMT) | TCSTATUS_A);
 168
 169        write_tc_c0_tchalt(0);
 170
 171        /* enable the VPE */
 172        write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
 173
 174        /* stack pointer */
 175        write_tc_gpr_sp( __KSTK_TOS(idle));
 176
 177        /* global pointer */
 178        write_tc_gpr_gp((unsigned long)gp);
 179
 180        flush_icache_range((unsigned long)gp,
 181                           (unsigned long)(gp + sizeof(struct thread_info)));
 182
 183        /* finally out of configuration and into chaos */
 184        clear_c0_mvpcontrol(MVPCONTROL_VPC);
 185
 186        evpe(EVPE_ENABLE);
 187}
 188
 189/*
 190 * Common setup before any secondaries are started
 191 * Make sure all CPU's are in a sensible state before we boot any of the
 192 * secondaries
 193 */
 194static void __init vsmp_smp_setup(void)
 195{
 196        unsigned int mvpconf0, ntc, tc, ncpu = 0;
 197        unsigned int nvpe;
 198
 199#ifdef CONFIG_MIPS_MT_FPAFF
 200        /* If we have an FPU, enroll ourselves in the FPU-full mask */
 201        if (cpu_has_fpu)
 202                cpumask_set_cpu(0, &mt_fpu_cpumask);
 203#endif /* CONFIG_MIPS_MT_FPAFF */
 204        if (!cpu_has_mipsmt)
 205                return;
 206
 207        /* disable MT so we can configure */
 208        dvpe();
 209        dmt();
 210
 211        /* Put MVPE's into 'configuration state' */
 212        set_c0_mvpcontrol(MVPCONTROL_VPC);
 213
 214        mvpconf0 = read_c0_mvpconf0();
 215        ntc = (mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT;
 216
 217        nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
 218        smp_num_siblings = nvpe;
 219
 220        /* we'll always have more TC's than VPE's, so loop setting everything
 221           to a sensible state */
 222        for (tc = 0; tc <= ntc; tc++) {
 223                settc(tc);
 224
 225                smvp_tc_init(tc, mvpconf0);
 226                ncpu = smvp_vpe_init(tc, mvpconf0, ncpu);
 227        }
 228
 229        /* Release config state */
 230        clear_c0_mvpcontrol(MVPCONTROL_VPC);
 231
 232        /* We'll wait until starting the secondaries before starting MVPE */
 233
 234        printk(KERN_INFO "Detected %i available secondary CPU(s)\n", ncpu);
 235}
 236
 237static void __init vsmp_prepare_cpus(unsigned int max_cpus)
 238{
 239        mips_mt_set_cpuoptions();
 240}
 241
 242struct plat_smp_ops vsmp_smp_ops = {
 243        .send_ipi_single        = mips_smp_send_ipi_single,
 244        .send_ipi_mask          = mips_smp_send_ipi_mask,
 245        .init_secondary         = vsmp_init_secondary,
 246        .smp_finish             = vsmp_smp_finish,
 247        .boot_secondary         = vsmp_boot_secondary,
 248        .smp_setup              = vsmp_smp_setup,
 249        .prepare_cpus           = vsmp_prepare_cpus,
 250};
 251
 252