• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2004-2008 Cavium Networks
7  */
8 #include <linux/init.h>
9 #include <linux/delay.h>
10 #include <linux/smp.h>
11 #include <linux/interrupt.h>
12 #include <linux/kernel_stat.h>
13 #include <linux/sched.h>
14 #include <linux/module.h>
15 
16 #include <asm/mmu_context.h>
17 #include <asm/system.h>
18 #include <asm/time.h>
19 
20 #include <asm/octeon/octeon.h>
21 
22 volatile unsigned long octeon_processor_boot = 0xff;
23 volatile unsigned long octeon_processor_sp;
24 volatile unsigned long octeon_processor_gp;
25 
mailbox_interrupt(int irq,void * dev_id)26 static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
27 {
28 	const int coreid = cvmx_get_core_num();
29 	uint64_t action;
30 
31 	/* Load the mailbox register to figure out what we're supposed to do */
32 	action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid));
33 
34 	/* Clear the mailbox to clear the interrupt */
35 	cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action);
36 
37 	if (action & SMP_CALL_FUNCTION)
38 		smp_call_function_interrupt();
39 
40 	/* Check if we've been told to flush the icache */
41 	if (action & SMP_ICACHE_FLUSH)
42 		asm volatile ("synci 0($0)\n");
43 	return IRQ_HANDLED;
44 }
45 
46 /**
47  * Cause the function described by call_data to be executed on the passed
48  * cpu.  When the function has finished, increment the finished field of
49  * call_data.
50  */
octeon_send_ipi_single(int cpu,unsigned int action)51 void octeon_send_ipi_single(int cpu, unsigned int action)
52 {
53 	int coreid = cpu_logical_map(cpu);
54 	/*
55 	pr_info("SMP: Mailbox send cpu=%d, coreid=%d, action=%u\n", cpu,
56 	       coreid, action);
57 	*/
58 	cvmx_write_csr(CVMX_CIU_MBOX_SETX(coreid), action);
59 }
60 
octeon_send_ipi_mask(cpumask_t mask,unsigned int action)61 static inline void octeon_send_ipi_mask(cpumask_t mask, unsigned int action)
62 {
63 	unsigned int i;
64 
65 	for_each_cpu_mask(i, mask)
66 		octeon_send_ipi_single(i, action);
67 }
68 
69 /**
70  * Detect available CPUs, populate phys_cpu_present_map
71  */
octeon_smp_setup(void)72 static void octeon_smp_setup(void)
73 {
74 	const int coreid = cvmx_get_core_num();
75 	int cpus;
76 	int id;
77 
78 	int core_mask = octeon_get_boot_coremask();
79 
80 	cpus_clear(cpu_possible_map);
81 	__cpu_number_map[coreid] = 0;
82 	__cpu_logical_map[0] = coreid;
83 	cpu_set(0, cpu_possible_map);
84 
85 	cpus = 1;
86 	for (id = 0; id < 16; id++) {
87 		if ((id != coreid) && (core_mask & (1 << id))) {
88 			cpu_set(cpus, cpu_possible_map);
89 			__cpu_number_map[id] = cpus;
90 			__cpu_logical_map[cpus] = id;
91 			cpus++;
92 		}
93 	}
94 }
95 
96 /**
97  * Firmware CPU startup hook
98  *
99  */
octeon_boot_secondary(int cpu,struct task_struct * idle)100 static void octeon_boot_secondary(int cpu, struct task_struct *idle)
101 {
102 	int count;
103 
104 	pr_info("SMP: Booting CPU%02d (CoreId %2d)...\n", cpu,
105 		cpu_logical_map(cpu));
106 
107 	octeon_processor_sp = __KSTK_TOS(idle);
108 	octeon_processor_gp = (unsigned long)(task_thread_info(idle));
109 	octeon_processor_boot = cpu_logical_map(cpu);
110 	mb();
111 
112 	count = 10000;
113 	while (octeon_processor_sp && count) {
114 		/* Waiting for processor to get the SP and GP */
115 		udelay(1);
116 		count--;
117 	}
118 	if (count == 0)
119 		pr_err("Secondary boot timeout\n");
120 }
121 
122 /**
123  * After we've done initial boot, this function is called to allow the
124  * board code to clean up state, if needed
125  */
octeon_init_secondary(void)126 static void octeon_init_secondary(void)
127 {
128 	const int coreid = cvmx_get_core_num();
129 	union cvmx_ciu_intx_sum0 interrupt_enable;
130 
131 	octeon_check_cpu_bist();
132 	octeon_init_cvmcount();
133 	/*
134 	pr_info("SMP: CPU%d (CoreId %lu) started\n", cpu, coreid);
135 	*/
136 	/* Enable Mailbox interrupts to this core. These are the only
137 	   interrupts allowed on line 3 */
138 	cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), 0xffffffff);
139 	interrupt_enable.u64 = 0;
140 	interrupt_enable.s.mbox = 0x3;
141 	cvmx_write_csr(CVMX_CIU_INTX_EN0((coreid * 2)), interrupt_enable.u64);
142 	cvmx_write_csr(CVMX_CIU_INTX_EN0((coreid * 2 + 1)), 0);
143 	cvmx_write_csr(CVMX_CIU_INTX_EN1((coreid * 2)), 0);
144 	cvmx_write_csr(CVMX_CIU_INTX_EN1((coreid * 2 + 1)), 0);
145 	/* Enable core interrupt processing for 2,3 and 7 */
146 	set_c0_status(0x8c01);
147 }
148 
149 /**
150  * Callout to firmware before smp_init
151  *
152  */
octeon_prepare_cpus(unsigned int max_cpus)153 void octeon_prepare_cpus(unsigned int max_cpus)
154 {
155 	cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffffffff);
156 	if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, IRQF_SHARED,
157 			"mailbox0", mailbox_interrupt)) {
158 		panic("Cannot request_irq(OCTEON_IRQ_MBOX0)\n");
159 	}
160 	if (request_irq(OCTEON_IRQ_MBOX1, mailbox_interrupt, IRQF_SHARED,
161 			"mailbox1", mailbox_interrupt)) {
162 		panic("Cannot request_irq(OCTEON_IRQ_MBOX1)\n");
163 	}
164 }
165 
166 /**
167  * Last chance for the board code to finish SMP initialization before
168  * the CPU is "online".
169  */
octeon_smp_finish(void)170 static void octeon_smp_finish(void)
171 {
172 #ifdef CONFIG_CAVIUM_GDB
173 	unsigned long tmp;
174 	/* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0
175 	   to be not masked by this core so we know the signal is received by
176 	   someone */
177 	asm volatile ("dmfc0 %0, $22\n"
178 		      "ori   %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp));
179 #endif
180 
181 	octeon_user_io_init();
182 
183 	/* to generate the first CPU timer interrupt */
184 	write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
185 }
186 
187 /**
188  * Hook for after all CPUs are online
189  */
octeon_cpus_done(void)190 static void octeon_cpus_done(void)
191 {
192 #ifdef CONFIG_CAVIUM_GDB
193 	unsigned long tmp;
194 	/* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0
195 	   to be not masked by this core so we know the signal is received by
196 	   someone */
197 	asm volatile ("dmfc0 %0, $22\n"
198 		      "ori   %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp));
199 #endif
200 }
201 
202 struct plat_smp_ops octeon_smp_ops = {
203 	.send_ipi_single	= octeon_send_ipi_single,
204 	.send_ipi_mask		= octeon_send_ipi_mask,
205 	.init_secondary		= octeon_init_secondary,
206 	.smp_finish		= octeon_smp_finish,
207 	.cpus_done		= octeon_cpus_done,
208 	.boot_secondary		= octeon_boot_secondary,
209 	.smp_setup		= octeon_smp_setup,
210 	.prepare_cpus		= octeon_prepare_cpus,
211 };
212