Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * SMP support for BPA machines.
0004  *
0005  * Dave Engebretsen, Peter Bergner, and
0006  * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
0007  *
0008  * Plus various changes from other IBM teams...
0009  */
0010 
0011 #undef DEBUG
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/sched.h>
0015 #include <linux/smp.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/delay.h>
0018 #include <linux/init.h>
0019 #include <linux/spinlock.h>
0020 #include <linux/cache.h>
0021 #include <linux/err.h>
0022 #include <linux/device.h>
0023 #include <linux/cpu.h>
0024 #include <linux/pgtable.h>
0025 
0026 #include <asm/ptrace.h>
0027 #include <linux/atomic.h>
0028 #include <asm/irq.h>
0029 #include <asm/page.h>
0030 #include <asm/io.h>
0031 #include <asm/smp.h>
0032 #include <asm/paca.h>
0033 #include <asm/machdep.h>
0034 #include <asm/cputable.h>
0035 #include <asm/firmware.h>
0036 #include <asm/rtas.h>
0037 #include <asm/cputhreads.h>
0038 #include <asm/code-patching.h>
0039 
0040 #include "interrupt.h"
0041 #include <asm/udbg.h>
0042 
0043 #ifdef DEBUG
0044 #define DBG(fmt...) udbg_printf(fmt)
0045 #else
0046 #define DBG(fmt...)
0047 #endif
0048 
0049 /*
0050  * The Primary thread of each non-boot processor was started from the OF client
0051  * interface by prom_hold_cpus and is spinning on secondary_hold_spinloop.
0052  */
0053 static cpumask_t of_spin_map;
0054 
0055 /**
0056  * smp_startup_cpu() - start the given cpu
0057  *
0058  * At boot time, there is nothing to do for primary threads which were
0059  * started from Open Firmware.  For anything else, call RTAS with the
0060  * appropriate start location.
0061  *
0062  * Returns:
0063  *  0   - failure
0064  *  1   - success
0065  */
0066 static inline int smp_startup_cpu(unsigned int lcpu)
0067 {
0068     int status;
0069     unsigned long start_here =
0070             __pa(ppc_function_entry(generic_secondary_smp_init));
0071     unsigned int pcpu;
0072     int start_cpu;
0073 
0074     if (cpumask_test_cpu(lcpu, &of_spin_map))
0075         /* Already started by OF and sitting in spin loop */
0076         return 1;
0077 
0078     pcpu = get_hard_smp_processor_id(lcpu);
0079 
0080     /*
0081      * If the RTAS start-cpu token does not exist then presume the
0082      * cpu is already spinning.
0083      */
0084     start_cpu = rtas_token("start-cpu");
0085     if (start_cpu == RTAS_UNKNOWN_SERVICE)
0086         return 1;
0087 
0088     status = rtas_call(start_cpu, 3, 1, NULL, pcpu, start_here, lcpu);
0089     if (status != 0) {
0090         printk(KERN_ERR "start-cpu failed: %i\n", status);
0091         return 0;
0092     }
0093 
0094     return 1;
0095 }
0096 
0097 static void smp_cell_setup_cpu(int cpu)
0098 {
0099     if (cpu != boot_cpuid)
0100         iic_setup_cpu();
0101 
0102     /*
0103      * change default DABRX to allow user watchpoints
0104      */
0105     mtspr(SPRN_DABRX, DABRX_KERNEL | DABRX_USER);
0106 }
0107 
0108 static int smp_cell_kick_cpu(int nr)
0109 {
0110     if (nr < 0 || nr >= nr_cpu_ids)
0111         return -EINVAL;
0112 
0113     if (!smp_startup_cpu(nr))
0114         return -ENOENT;
0115 
0116     /*
0117      * The processor is currently spinning, waiting for the
0118      * cpu_start field to become non-zero After we set cpu_start,
0119      * the processor will continue on to secondary_start
0120      */
0121     paca_ptrs[nr]->cpu_start = 1;
0122 
0123     return 0;
0124 }
0125 
0126 static struct smp_ops_t bpa_iic_smp_ops = {
0127     .message_pass   = iic_message_pass,
0128     .probe      = iic_request_IPIs,
0129     .kick_cpu   = smp_cell_kick_cpu,
0130     .setup_cpu  = smp_cell_setup_cpu,
0131     .cpu_bootable   = smp_generic_cpu_bootable,
0132 };
0133 
0134 /* This is called very early */
0135 void __init smp_init_cell(void)
0136 {
0137     int i;
0138 
0139     DBG(" -> smp_init_cell()\n");
0140 
0141     smp_ops = &bpa_iic_smp_ops;
0142 
0143     /* Mark threads which are still spinning in hold loops. */
0144     if (cpu_has_feature(CPU_FTR_SMT)) {
0145         for_each_present_cpu(i) {
0146             if (cpu_thread_in_core(i) == 0)
0147                 cpumask_set_cpu(i, &of_spin_map);
0148         }
0149     } else
0150         cpumask_copy(&of_spin_map, cpu_present_mask);
0151 
0152     cpumask_clear_cpu(boot_cpuid, &of_spin_map);
0153 
0154     /* Non-lpar has additional take/give timebase */
0155     if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
0156         smp_ops->give_timebase = rtas_give_timebase;
0157         smp_ops->take_timebase = rtas_take_timebase;
0158     }
0159 
0160     DBG(" <- smp_init_cell()\n");
0161 }