root/arch/sparc/kernel/sun4m_smp.c

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

DEFINITIONS

This source file includes following definitions.
  1. swap_ulong
  2. sun4m_cpu_pre_starting
  3. sun4m_cpu_pre_online
  4. smp4m_boot_cpus
  5. smp4m_boot_one_cpu
  6. smp4m_smp_done
  7. sun4m_send_ipi
  8. sun4m_ipi_resched
  9. sun4m_ipi_single
  10. sun4m_ipi_mask_one
  11. sun4m_cross_call
  12. smp4m_cross_call_irq
  13. smp4m_percpu_timer_interrupt
  14. sun4m_init_smp

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *  sun4m SMP support.
   4  *
   5  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
   6  */
   7 
   8 #include <linux/clockchips.h>
   9 #include <linux/interrupt.h>
  10 #include <linux/profile.h>
  11 #include <linux/delay.h>
  12 #include <linux/sched/mm.h>
  13 #include <linux/cpu.h>
  14 
  15 #include <asm/cacheflush.h>
  16 #include <asm/switch_to.h>
  17 #include <asm/tlbflush.h>
  18 #include <asm/timer.h>
  19 #include <asm/oplib.h>
  20 
  21 #include "irq.h"
  22 #include "kernel.h"
  23 
  24 #define IRQ_IPI_SINGLE          12
  25 #define IRQ_IPI_MASK            13
  26 #define IRQ_IPI_RESCHED         14
  27 #define IRQ_CROSS_CALL          15
  28 
  29 static inline unsigned long
  30 swap_ulong(volatile unsigned long *ptr, unsigned long val)
  31 {
  32         __asm__ __volatile__("swap [%1], %0\n\t" :
  33                              "=&r" (val), "=&r" (ptr) :
  34                              "0" (val), "1" (ptr));
  35         return val;
  36 }
  37 
  38 void sun4m_cpu_pre_starting(void *arg)
  39 {
  40 }
  41 
  42 void sun4m_cpu_pre_online(void *arg)
  43 {
  44         int cpuid = hard_smp_processor_id();
  45 
  46         /* Allow master to continue. The master will then give us the
  47          * go-ahead by setting the smp_commenced_mask and will wait without
  48          * timeouts until our setup is completed fully (signified by
  49          * our bit being set in the cpu_online_mask).
  50          */
  51         swap_ulong(&cpu_callin_map[cpuid], 1);
  52 
  53         /* XXX: What's up with all the flushes? */
  54         local_ops->cache_all();
  55         local_ops->tlb_all();
  56 
  57         /* Fix idle thread fields. */
  58         __asm__ __volatile__("ld [%0], %%g6\n\t"
  59                              : : "r" (&current_set[cpuid])
  60                              : "memory" /* paranoid */);
  61 
  62         /* Attach to the address space of init_task. */
  63         mmgrab(&init_mm);
  64         current->active_mm = &init_mm;
  65 
  66         while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
  67                 mb();
  68 }
  69 
  70 /*
  71  *      Cycle through the processors asking the PROM to start each one.
  72  */
  73 void __init smp4m_boot_cpus(void)
  74 {
  75         sun4m_unmask_profile_irq();
  76         local_ops->cache_all();
  77 }
  78 
  79 int smp4m_boot_one_cpu(int i, struct task_struct *idle)
  80 {
  81         unsigned long *entry = &sun4m_cpu_startup;
  82         int timeout;
  83         int cpu_node;
  84 
  85         cpu_find_by_mid(i, &cpu_node);
  86         current_set[i] = task_thread_info(idle);
  87 
  88         /* See trampoline.S for details... */
  89         entry += ((i - 1) * 3);
  90 
  91         /*
  92          * Initialize the contexts table
  93          * Since the call to prom_startcpu() trashes the structure,
  94          * we need to re-initialize it for each cpu
  95          */
  96         smp_penguin_ctable.which_io = 0;
  97         smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
  98         smp_penguin_ctable.reg_size = 0;
  99 
 100         /* whirrr, whirrr, whirrrrrrrrr... */
 101         printk(KERN_INFO "Starting CPU %d at %p\n", i, entry);
 102         local_ops->cache_all();
 103         prom_startcpu(cpu_node, &smp_penguin_ctable, 0, (char *)entry);
 104 
 105         /* wheee... it's going... */
 106         for (timeout = 0; timeout < 10000; timeout++) {
 107                 if (cpu_callin_map[i])
 108                         break;
 109                 udelay(200);
 110         }
 111 
 112         if (!(cpu_callin_map[i])) {
 113                 printk(KERN_ERR "Processor %d is stuck.\n", i);
 114                 return -ENODEV;
 115         }
 116 
 117         local_ops->cache_all();
 118         return 0;
 119 }
 120 
 121 void __init smp4m_smp_done(void)
 122 {
 123         int i, first;
 124         int *prev;
 125 
 126         /* setup cpu list for irq rotation */
 127         first = 0;
 128         prev = &first;
 129         for_each_online_cpu(i) {
 130                 *prev = i;
 131                 prev = &cpu_data(i).next;
 132         }
 133         *prev = first;
 134         local_ops->cache_all();
 135 
 136         /* Ok, they are spinning and ready to go. */
 137 }
 138 
 139 static void sun4m_send_ipi(int cpu, int level)
 140 {
 141         sbus_writel(SUN4M_SOFT_INT(level), &sun4m_irq_percpu[cpu]->set);
 142 }
 143 
 144 static void sun4m_ipi_resched(int cpu)
 145 {
 146         sun4m_send_ipi(cpu, IRQ_IPI_RESCHED);
 147 }
 148 
 149 static void sun4m_ipi_single(int cpu)
 150 {
 151         sun4m_send_ipi(cpu, IRQ_IPI_SINGLE);
 152 }
 153 
 154 static void sun4m_ipi_mask_one(int cpu)
 155 {
 156         sun4m_send_ipi(cpu, IRQ_IPI_MASK);
 157 }
 158 
 159 static struct smp_funcall {
 160         smpfunc_t func;
 161         unsigned long arg1;
 162         unsigned long arg2;
 163         unsigned long arg3;
 164         unsigned long arg4;
 165         unsigned long arg5;
 166         unsigned long processors_in[SUN4M_NCPUS];  /* Set when ipi entered. */
 167         unsigned long processors_out[SUN4M_NCPUS]; /* Set when ipi exited. */
 168 } ccall_info;
 169 
 170 static DEFINE_SPINLOCK(cross_call_lock);
 171 
 172 /* Cross calls must be serialized, at least currently. */
 173 static void sun4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
 174                              unsigned long arg2, unsigned long arg3,
 175                              unsigned long arg4)
 176 {
 177                 register int ncpus = SUN4M_NCPUS;
 178                 unsigned long flags;
 179 
 180                 spin_lock_irqsave(&cross_call_lock, flags);
 181 
 182                 /* Init function glue. */
 183                 ccall_info.func = func;
 184                 ccall_info.arg1 = arg1;
 185                 ccall_info.arg2 = arg2;
 186                 ccall_info.arg3 = arg3;
 187                 ccall_info.arg4 = arg4;
 188                 ccall_info.arg5 = 0;
 189 
 190                 /* Init receive/complete mapping, plus fire the IPI's off. */
 191                 {
 192                         register int i;
 193 
 194                         cpumask_clear_cpu(smp_processor_id(), &mask);
 195                         cpumask_and(&mask, cpu_online_mask, &mask);
 196                         for (i = 0; i < ncpus; i++) {
 197                                 if (cpumask_test_cpu(i, &mask)) {
 198                                         ccall_info.processors_in[i] = 0;
 199                                         ccall_info.processors_out[i] = 0;
 200                                         sun4m_send_ipi(i, IRQ_CROSS_CALL);
 201                                 } else {
 202                                         ccall_info.processors_in[i] = 1;
 203                                         ccall_info.processors_out[i] = 1;
 204                                 }
 205                         }
 206                 }
 207 
 208                 {
 209                         register int i;
 210 
 211                         i = 0;
 212                         do {
 213                                 if (!cpumask_test_cpu(i, &mask))
 214                                         continue;
 215                                 while (!ccall_info.processors_in[i])
 216                                         barrier();
 217                         } while (++i < ncpus);
 218 
 219                         i = 0;
 220                         do {
 221                                 if (!cpumask_test_cpu(i, &mask))
 222                                         continue;
 223                                 while (!ccall_info.processors_out[i])
 224                                         barrier();
 225                         } while (++i < ncpus);
 226                 }
 227                 spin_unlock_irqrestore(&cross_call_lock, flags);
 228 }
 229 
 230 /* Running cross calls. */
 231 void smp4m_cross_call_irq(void)
 232 {
 233         int i = smp_processor_id();
 234 
 235         ccall_info.processors_in[i] = 1;
 236         ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
 237                         ccall_info.arg4, ccall_info.arg5);
 238         ccall_info.processors_out[i] = 1;
 239 }
 240 
 241 void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
 242 {
 243         struct pt_regs *old_regs;
 244         struct clock_event_device *ce;
 245         int cpu = smp_processor_id();
 246 
 247         old_regs = set_irq_regs(regs);
 248 
 249         ce = &per_cpu(sparc32_clockevent, cpu);
 250 
 251         if (clockevent_state_periodic(ce))
 252                 sun4m_clear_profile_irq(cpu);
 253         else
 254                 sparc_config.load_profile_irq(cpu, 0); /* Is this needless? */
 255 
 256         irq_enter();
 257         ce->event_handler(ce);
 258         irq_exit();
 259 
 260         set_irq_regs(old_regs);
 261 }
 262 
 263 static const struct sparc32_ipi_ops sun4m_ipi_ops = {
 264         .cross_call = sun4m_cross_call,
 265         .resched    = sun4m_ipi_resched,
 266         .single     = sun4m_ipi_single,
 267         .mask_one   = sun4m_ipi_mask_one,
 268 };
 269 
 270 void __init sun4m_init_smp(void)
 271 {
 272         sparc32_ipi_ops = &sun4m_ipi_ops;
 273 }

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