smp.c 6.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
/*
 * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
 * reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the NetLogic
 * license below:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/irq.h>

#include <asm/mmu_context.h>

#include <asm/netlogic/interrupt.h>
#include <asm/netlogic/mips-extns.h>
45 46
#include <asm/netlogic/haldefs.h>
#include <asm/netlogic/common.h>
47

48 49
#if defined(CONFIG_CPU_XLP)
#include <asm/netlogic/xlp-hal/iomap.h>
50
#include <asm/netlogic/xlp-hal/xlp.h>
51 52
#include <asm/netlogic/xlp-hal/pic.h>
#elif defined(CONFIG_CPU_XLR)
53 54
#include <asm/netlogic/xlr/iomap.h>
#include <asm/netlogic/xlr/pic.h>
55
#include <asm/netlogic/xlr/xlr.h>
56 57 58
#else
#error "Unknown CPU"
#endif
59

60
void nlm_send_ipi_single(int logical_cpu, unsigned int action)
61 62 63 64
{
	int cpu = cpu_logical_map(logical_cpu);

	if (action & SMP_CALL_FUNCTION)
65 66 67
		nlm_pic_send_ipi(nlm_pic_base, cpu, IRQ_IPI_SMP_FUNCTION, 0);
	if (action & SMP_RESCHEDULE_YOURSELF)
		nlm_pic_send_ipi(nlm_pic_base, cpu, IRQ_IPI_SMP_RESCHEDULE, 0);
68 69 70 71 72 73 74
}

void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action)
{
	int cpu;

	for_each_cpu(cpu, mask) {
75
		nlm_send_ipi_single(cpu, action);
76 77 78 79 80 81
	}
}

/* IRQ_IPI_SMP_FUNCTION Handler */
void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc)
{
82
	write_c0_eirr(1ull << irq);
83
	smp_call_function_interrupt();
84 85 86 87 88
}

/* IRQ_IPI_SMP_RESCHEDULE  handler */
void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc)
{
89
	write_c0_eirr(1ull << irq);
90
	scheduler_ipi();
91 92 93 94 95
}

/*
 * Called before going into mips code, early cpu init
 */
96
void nlm_early_init_secondary(int cpu)
97
{
98
	change_c0_config(CONF_CM_CMASK, 0x3);
99
	write_c0_ebase((uint32_t)nlm_common_ebase);
100
#ifdef CONFIG_CPU_XLP
101
	if (cpu % 4 == 0)
102 103
		xlp_mmu_init();
#endif
104 105 106 107 108 109 110
}

/*
 * Code to run on secondary just after probing the CPU
 */
static void __cpuinit nlm_init_secondary(void)
{
111
	current_cpu_data.core = hard_smp_processor_id() / 4;
112 113 114
	nlm_smp_irq_init();
}

115 116 117 118 119 120
void nlm_prepare_cpus(unsigned int max_cpus)
{
	/* declare we are SMT capable */
	smp_num_siblings = nlm_threads_per_core;
}

121 122 123 124 125
void nlm_smp_finish(void)
{
#ifdef notyet
	nlm_common_msgring_cpu_init();
#endif
126
	local_irq_enable();
127 128 129 130 131 132 133 134 135 136 137 138 139
}

void nlm_cpus_done(void)
{
}

/*
 * Boot all other cpus in the system, initialize them, and bring them into
 * the boot function
 */
int nlm_cpu_ready[NR_CPUS];
unsigned long nlm_next_gp;
unsigned long nlm_next_sp;
140

141 142 143 144 145 146 147 148 149 150 151 152 153
cpumask_t phys_cpu_present_map;

void nlm_boot_secondary(int logical_cpu, struct task_struct *idle)
{
	unsigned long gp = (unsigned long)task_thread_info(idle);
	unsigned long sp = (unsigned long)__KSTK_TOS(idle);
	int cpu = cpu_logical_map(logical_cpu);

	nlm_next_sp = sp;
	nlm_next_gp = gp;

	/* barrier */
	__sync();
154
	nlm_pic_send_ipi(nlm_pic_base, cpu, 1, 1);
155 156 157 158 159 160 161 162 163 164 165 166 167
}

void __init nlm_smp_setup(void)
{
	unsigned int boot_cpu;
	int num_cpus, i;

	boot_cpu = hard_smp_processor_id();
	cpus_clear(phys_cpu_present_map);

	cpu_set(boot_cpu, phys_cpu_present_map);
	__cpu_number_map[boot_cpu] = 0;
	__cpu_logical_map[0] = boot_cpu;
168
	set_cpu_possible(0, true);
169 170 171

	num_cpus = 1;
	for (i = 0; i < NR_CPUS; i++) {
172
		/*
173 174
		 * nlm_cpu_ready array is not set for the boot_cpu,
		 * it is only set for ASPs (see smpboot.S)
175
		 */
176 177 178 179
		if (nlm_cpu_ready[i]) {
			cpu_set(i, phys_cpu_present_map);
			__cpu_number_map[i] = num_cpus;
			__cpu_logical_map[num_cpus] = i;
180
			set_cpu_possible(num_cpus, true);
181 182 183 184 185 186
			++num_cpus;
		}
	}

	pr_info("Phys CPU present map: %lx, possible map %lx\n",
		(unsigned long)phys_cpu_present_map.bits[0],
187
		(unsigned long)cpumask_bits(cpu_possible_mask)[0]);
188 189

	pr_info("Detected %i Slave CPU(s)\n", num_cpus);
190
	nlm_set_nmi_handler(nlm_boot_secondary_cpus);
191 192
}

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
static int nlm_parse_cpumask(u32 cpu_mask)
{
	uint32_t core0_thr_mask, core_thr_mask;
	int threadmode, i;

	core0_thr_mask = cpu_mask & 0xf;
	switch (core0_thr_mask) {
	case 1:
		nlm_threads_per_core = 1;
		threadmode = 0;
		break;
	case 3:
		nlm_threads_per_core = 2;
		threadmode = 2;
		break;
	case 0xf:
		nlm_threads_per_core = 4;
		threadmode = 3;
		break;
	default:
		goto unsupp;
	}

	/* Verify other cores CPU masks */
	nlm_coremask = 1;
	nlm_cpumask = core0_thr_mask;
	for (i = 1; i < 8; i++) {
		core_thr_mask = (cpu_mask >> (i * 4)) & 0xf;
		if (core_thr_mask) {
			if (core_thr_mask != core0_thr_mask)
				goto unsupp;
			nlm_coremask |= 1 << i;
			nlm_cpumask |= core0_thr_mask << (4 * i);
		}
	}
	return threadmode;

unsupp:
	panic("Unsupported CPU mask %x\n", cpu_mask);
	return 0;
}

int __cpuinit nlm_wakeup_secondary_cpus(u32 wakeup_mask)
{
	unsigned long reset_vec;
	char *reset_data;
	int threadmode;

	/* Update reset entry point with CPU init code */
	reset_vec = CKSEG1ADDR(RESET_VEC_PHYS);
	memcpy((void *)reset_vec, (void *)nlm_reset_entry,
			(nlm_reset_entry_end - nlm_reset_entry));

	/* verify the mask and setup core config variables */
	threadmode = nlm_parse_cpumask(wakeup_mask);

	/* Setup CPU init parameters */
	reset_data = (char *)CKSEG1ADDR(RESET_DATA_PHYS);
	*(int *)(reset_data + BOOT_THREAD_MODE) = threadmode;

#ifdef CONFIG_CPU_XLP
	xlp_wakeup_secondary_cpus();
#else
	xlr_wakeup_secondary_cpus();
#endif
	return 0;
}

261 262 263 264 265 266 267 268 269 270
struct plat_smp_ops nlm_smp_ops = {
	.send_ipi_single	= nlm_send_ipi_single,
	.send_ipi_mask		= nlm_send_ipi_mask,
	.init_secondary		= nlm_init_secondary,
	.smp_finish		= nlm_smp_finish,
	.cpus_done		= nlm_cpus_done,
	.boot_secondary		= nlm_boot_secondary,
	.smp_setup		= nlm_smp_setup,
	.prepare_cpus		= nlm_prepare_cpus,
};