0001
0002
0003
0004
0005
0006
0007
0008
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
0051
0052
0053 static cpumask_t of_spin_map;
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
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
0076 return 1;
0077
0078 pcpu = get_hard_smp_processor_id(lcpu);
0079
0080
0081
0082
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
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
0118
0119
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
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
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
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 }