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