Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Sparc SS1000/SC2000 SMP support.
0003  *
0004  * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
0005  *
0006  * Based on sun4m's smp.c, which is:
0007  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
0008  */
0009 
0010 #include <linux/clockchips.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/profile.h>
0013 #include <linux/delay.h>
0014 #include <linux/sched/mm.h>
0015 #include <linux/cpu.h>
0016 
0017 #include <asm/cacheflush.h>
0018 #include <asm/switch_to.h>
0019 #include <asm/tlbflush.h>
0020 #include <asm/timer.h>
0021 #include <asm/oplib.h>
0022 #include <asm/sbi.h>
0023 #include <asm/mmu.h>
0024 
0025 #include "kernel.h"
0026 #include "irq.h"
0027 
0028 #define IRQ_CROSS_CALL      15
0029 
0030 static volatile int smp_processors_ready;
0031 static int smp_highest_cpu;
0032 
0033 static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned long val)
0034 {
0035     __asm__ __volatile__("swap [%1], %0\n\t" :
0036                  "=&r" (val), "=&r" (ptr) :
0037                  "0" (val), "1" (ptr));
0038     return val;
0039 }
0040 
0041 static void smp4d_ipi_init(void);
0042 
0043 static unsigned char cpu_leds[32];
0044 
0045 static inline void show_leds(int cpuid)
0046 {
0047     cpuid &= 0x1e;
0048     __asm__ __volatile__ ("stba %0, [%1] %2" : :
0049                   "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
0050                   "r" (ECSR_BASE(cpuid) | BB_LEDS),
0051                   "i" (ASI_M_CTL));
0052 }
0053 
0054 void sun4d_cpu_pre_starting(void *arg)
0055 {
0056     int cpuid = hard_smp_processor_id();
0057 
0058     /* Show we are alive */
0059     cpu_leds[cpuid] = 0x6;
0060     show_leds(cpuid);
0061 
0062     /* Enable level15 interrupt, disable level14 interrupt for now */
0063     cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000);
0064 }
0065 
0066 void sun4d_cpu_pre_online(void *arg)
0067 {
0068     unsigned long flags;
0069     int cpuid;
0070 
0071     cpuid = hard_smp_processor_id();
0072 
0073     /* Unblock the master CPU _only_ when the scheduler state
0074      * of all secondary CPUs will be up-to-date, so after
0075      * the SMP initialization the master will be just allowed
0076      * to call the scheduler code.
0077      */
0078     sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1);
0079     local_ops->cache_all();
0080     local_ops->tlb_all();
0081 
0082     while ((unsigned long)current_set[cpuid] < PAGE_OFFSET)
0083         barrier();
0084 
0085     while (current_set[cpuid]->cpu != cpuid)
0086         barrier();
0087 
0088     /* Fix idle thread fields. */
0089     __asm__ __volatile__("ld [%0], %%g6\n\t"
0090                  : : "r" (&current_set[cpuid])
0091                  : "memory" /* paranoid */);
0092 
0093     cpu_leds[cpuid] = 0x9;
0094     show_leds(cpuid);
0095 
0096     /* Attach to the address space of init_task. */
0097     mmgrab(&init_mm);
0098     current->active_mm = &init_mm;
0099 
0100     local_ops->cache_all();
0101     local_ops->tlb_all();
0102 
0103     while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
0104         barrier();
0105 
0106     spin_lock_irqsave(&sun4d_imsk_lock, flags);
0107     cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */
0108     spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
0109 }
0110 
0111 /*
0112  *  Cycle through the processors asking the PROM to start each one.
0113  */
0114 void __init smp4d_boot_cpus(void)
0115 {
0116     smp4d_ipi_init();
0117     if (boot_cpu_id)
0118         current_set[0] = NULL;
0119     local_ops->cache_all();
0120 }
0121 
0122 int smp4d_boot_one_cpu(int i, struct task_struct *idle)
0123 {
0124     unsigned long *entry = &sun4d_cpu_startup;
0125     int timeout;
0126     int cpu_node;
0127 
0128     cpu_find_by_instance(i, &cpu_node, NULL);
0129     current_set[i] = task_thread_info(idle);
0130     /*
0131      * Initialize the contexts table
0132      * Since the call to prom_startcpu() trashes the structure,
0133      * we need to re-initialize it for each cpu
0134      */
0135     smp_penguin_ctable.which_io = 0;
0136     smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
0137     smp_penguin_ctable.reg_size = 0;
0138 
0139     /* whirrr, whirrr, whirrrrrrrrr... */
0140     printk(KERN_INFO "Starting CPU %d at %p\n", i, entry);
0141     local_ops->cache_all();
0142     prom_startcpu(cpu_node,
0143               &smp_penguin_ctable, 0, (char *)entry);
0144 
0145     printk(KERN_INFO "prom_startcpu returned :)\n");
0146 
0147     /* wheee... it's going... */
0148     for (timeout = 0; timeout < 10000; timeout++) {
0149         if (cpu_callin_map[i])
0150             break;
0151         udelay(200);
0152     }
0153 
0154     if (!(cpu_callin_map[i])) {
0155         printk(KERN_ERR "Processor %d is stuck.\n", i);
0156         return -ENODEV;
0157 
0158     }
0159     local_ops->cache_all();
0160     return 0;
0161 }
0162 
0163 void __init smp4d_smp_done(void)
0164 {
0165     int i, first;
0166     int *prev;
0167 
0168     /* setup cpu list for irq rotation */
0169     first = 0;
0170     prev = &first;
0171     for_each_online_cpu(i) {
0172         *prev = i;
0173         prev = &cpu_data(i).next;
0174     }
0175     *prev = first;
0176     local_ops->cache_all();
0177 
0178     /* Ok, they are spinning and ready to go. */
0179     smp_processors_ready = 1;
0180     sun4d_distribute_irqs();
0181 }
0182 
0183 /* Memory structure giving interrupt handler information about IPI generated */
0184 struct sun4d_ipi_work {
0185     int single;
0186     int msk;
0187     int resched;
0188 };
0189 
0190 static DEFINE_PER_CPU_SHARED_ALIGNED(struct sun4d_ipi_work, sun4d_ipi_work);
0191 
0192 /* Initialize IPIs on the SUN4D SMP machine */
0193 static void __init smp4d_ipi_init(void)
0194 {
0195     int cpu;
0196     struct sun4d_ipi_work *work;
0197 
0198     printk(KERN_INFO "smp4d: setup IPI at IRQ %d\n", SUN4D_IPI_IRQ);
0199 
0200     for_each_possible_cpu(cpu) {
0201         work = &per_cpu(sun4d_ipi_work, cpu);
0202         work->single = work->msk = work->resched = 0;
0203     }
0204 }
0205 
0206 void sun4d_ipi_interrupt(void)
0207 {
0208     struct sun4d_ipi_work *work = this_cpu_ptr(&sun4d_ipi_work);
0209 
0210     if (work->single) {
0211         work->single = 0;
0212         smp_call_function_single_interrupt();
0213     }
0214     if (work->msk) {
0215         work->msk = 0;
0216         smp_call_function_interrupt();
0217     }
0218     if (work->resched) {
0219         work->resched = 0;
0220         smp_resched_interrupt();
0221     }
0222 }
0223 
0224 /* +-------+-------------+-----------+------------------------------------+
0225  * | bcast |  devid      |   sid     |              levels mask           |
0226  * +-------+-------------+-----------+------------------------------------+
0227  *  31      30         23 22       15 14                                 0
0228  */
0229 #define IGEN_MESSAGE(bcast, devid, sid, levels) \
0230     (((bcast) << 31) | ((devid) << 23) | ((sid) << 15) | (levels))
0231 
0232 static void sun4d_send_ipi(int cpu, int level)
0233 {
0234     cc_set_igen(IGEN_MESSAGE(0, cpu << 3, 6 + ((level >> 1) & 7), 1 << (level - 1)));
0235 }
0236 
0237 static void sun4d_ipi_single(int cpu)
0238 {
0239     struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu);
0240 
0241     /* Mark work */
0242     work->single = 1;
0243 
0244     /* Generate IRQ on the CPU */
0245     sun4d_send_ipi(cpu, SUN4D_IPI_IRQ);
0246 }
0247 
0248 static void sun4d_ipi_mask_one(int cpu)
0249 {
0250     struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu);
0251 
0252     /* Mark work */
0253     work->msk = 1;
0254 
0255     /* Generate IRQ on the CPU */
0256     sun4d_send_ipi(cpu, SUN4D_IPI_IRQ);
0257 }
0258 
0259 static void sun4d_ipi_resched(int cpu)
0260 {
0261     struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu);
0262 
0263     /* Mark work */
0264     work->resched = 1;
0265 
0266     /* Generate IRQ on the CPU (any IRQ will cause resched) */
0267     sun4d_send_ipi(cpu, SUN4D_IPI_IRQ);
0268 }
0269 
0270 static struct smp_funcall {
0271     void *func;
0272     unsigned long arg1;
0273     unsigned long arg2;
0274     unsigned long arg3;
0275     unsigned long arg4;
0276     unsigned long arg5;
0277     unsigned char processors_in[NR_CPUS];  /* Set when ipi entered. */
0278     unsigned char processors_out[NR_CPUS]; /* Set when ipi exited. */
0279 } ccall_info __attribute__((aligned(8)));
0280 
0281 static DEFINE_SPINLOCK(cross_call_lock);
0282 
0283 /* Cross calls must be serialized, at least currently. */
0284 static void sun4d_cross_call(void *func, cpumask_t mask, unsigned long arg1,
0285                  unsigned long arg2, unsigned long arg3,
0286                  unsigned long arg4)
0287 {
0288     if (smp_processors_ready) {
0289         register int high = smp_highest_cpu;
0290         unsigned long flags;
0291 
0292         spin_lock_irqsave(&cross_call_lock, flags);
0293 
0294         {
0295             /*
0296              * If you make changes here, make sure
0297              * gcc generates proper code...
0298              */
0299             register void *f asm("i0") = func;
0300             register unsigned long a1 asm("i1") = arg1;
0301             register unsigned long a2 asm("i2") = arg2;
0302             register unsigned long a3 asm("i3") = arg3;
0303             register unsigned long a4 asm("i4") = arg4;
0304             register unsigned long a5 asm("i5") = 0;
0305 
0306             __asm__ __volatile__(
0307                 "std %0, [%6]\n\t"
0308                 "std %2, [%6 + 8]\n\t"
0309                 "std %4, [%6 + 16]\n\t" : :
0310                 "r"(f), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5),
0311                 "r" (&ccall_info.func));
0312         }
0313 
0314         /* Init receive/complete mapping, plus fire the IPI's off. */
0315         {
0316             register int i;
0317 
0318             cpumask_clear_cpu(smp_processor_id(), &mask);
0319             cpumask_and(&mask, cpu_online_mask, &mask);
0320             for (i = 0; i <= high; i++) {
0321                 if (cpumask_test_cpu(i, &mask)) {
0322                     ccall_info.processors_in[i] = 0;
0323                     ccall_info.processors_out[i] = 0;
0324                     sun4d_send_ipi(i, IRQ_CROSS_CALL);
0325                 }
0326             }
0327         }
0328 
0329         {
0330             register int i;
0331 
0332             i = 0;
0333             do {
0334                 if (!cpumask_test_cpu(i, &mask))
0335                     continue;
0336                 while (!ccall_info.processors_in[i])
0337                     barrier();
0338             } while (++i <= high);
0339 
0340             i = 0;
0341             do {
0342                 if (!cpumask_test_cpu(i, &mask))
0343                     continue;
0344                 while (!ccall_info.processors_out[i])
0345                     barrier();
0346             } while (++i <= high);
0347         }
0348 
0349         spin_unlock_irqrestore(&cross_call_lock, flags);
0350     }
0351 }
0352 
0353 /* Running cross calls. */
0354 void smp4d_cross_call_irq(void)
0355 {
0356     void (*func)(unsigned long, unsigned long, unsigned long, unsigned long,
0357              unsigned long) = ccall_info.func;
0358     int i = hard_smp_processor_id();
0359 
0360     ccall_info.processors_in[i] = 1;
0361     func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3, ccall_info.arg4,
0362          ccall_info.arg5);
0363     ccall_info.processors_out[i] = 1;
0364 }
0365 
0366 void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
0367 {
0368     struct pt_regs *old_regs;
0369     int cpu = hard_smp_processor_id();
0370     struct clock_event_device *ce;
0371     static int cpu_tick[NR_CPUS];
0372     static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd };
0373 
0374     old_regs = set_irq_regs(regs);
0375     bw_get_prof_limit(cpu);
0376     bw_clear_intr_mask(0, 1);   /* INTR_TABLE[0] & 1 is Profile IRQ */
0377 
0378     cpu_tick[cpu]++;
0379     if (!(cpu_tick[cpu] & 15)) {
0380         if (cpu_tick[cpu] == 0x60)
0381             cpu_tick[cpu] = 0;
0382         cpu_leds[cpu] = led_mask[cpu_tick[cpu] >> 4];
0383         show_leds(cpu);
0384     }
0385 
0386     ce = &per_cpu(sparc32_clockevent, cpu);
0387 
0388     irq_enter();
0389     ce->event_handler(ce);
0390     irq_exit();
0391 
0392     set_irq_regs(old_regs);
0393 }
0394 
0395 static const struct sparc32_ipi_ops sun4d_ipi_ops = {
0396     .cross_call = sun4d_cross_call,
0397     .resched    = sun4d_ipi_resched,
0398     .single     = sun4d_ipi_single,
0399     .mask_one   = sun4d_ipi_mask_one,
0400 };
0401 
0402 void __init sun4d_init_smp(void)
0403 {
0404     int i;
0405 
0406     /* Patch ipi15 trap table */
0407     t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_sun4d - linux_trap_ipi15_sun4m);
0408 
0409     sparc32_ipi_ops = &sun4d_ipi_ops;
0410 
0411     for (i = 0; i < NR_CPUS; i++) {
0412         ccall_info.processors_in[i] = 1;
0413         ccall_info.processors_out[i] = 1;
0414     }
0415 }