root/arch/mips/kernel/smp-mt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smvp_copy_vpe_config
  2. smvp_vpe_init
  3. smvp_tc_init
  4. vsmp_init_secondary
  5. vsmp_smp_finish
  6. vsmp_boot_secondary
  7. vsmp_smp_setup
  8. vsmp_prepare_cpus

   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 
  29 static 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 
  46 static 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 
  80 static 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 
 108 static 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 
 120 static 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  */
 142 static 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  */
 183 static 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 
 226 static void __init vsmp_prepare_cpus(unsigned int max_cpus)
 227 {
 228         mips_mt_set_cpuoptions();
 229 }
 230 
 231 const 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 

/* [<][>][^][v][top][bottom][index][help] */