2 * Copyright 2003 PMC-Sierra
3 * Author: Manish Lachwani (lachwani@pmc-sierra.com)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include <linux/init.h>
21 #include <linux/delay.h>
22 #include <linux/smp.h>
23 #include <linux/kernel_stat.h>
25 #include <asm/mmu_context.h>
26 #include <asm/trace.h>
28 extern void asmlinkage
smp_bootstrap(void);
31 * Send inter-processor interrupt
33 void core_send_ipi(int cpu
, unsigned int action
)
36 * Generate and INTMSG so that it can be sent over to the destination CPU
37 * The INTMSG will put the STATUS bits based on the action desired
40 case SMP_RESCHEDULE_YOURSELF
:
43 case SMP_CALL_FUNCTION
:
45 *(volatile uint32_t *)(0xbb000a00) = 0x00610002;
47 *(volatile uint32_t *)(0xbb000a00) = 0x00610001;
51 panic("core_send_ipi \n");
56 * Mailbox interrupt to handle IPI
58 void jaguar_mailbox_irq(struct pt_regs
*regs
)
60 int cpu
= smp_processor_id();
62 /* SMP_CALL_FUNCTION */
63 smp_call_function_interrupt();
66 extern atomic_t cpus_booted
;
68 void __init
start_secondary(void)
70 unsigned int cpu
= smp_processor_id();
71 extern atomic_t smp_commenced
;
73 if (current
->processor
!= 1) {
74 printk("Impossible CPU %d \n", cpu
);
75 current
->processor
= 1;
76 current
->cpus_runnable
= 1 << 1;
77 cpu
= current
->processor
;
83 prom_init_secondary();
87 * XXX parity protection should be folded in here when it's converted
88 * to an option instead of something based on .cputype
90 pgd_current
[cpu
] = init_mm
.pgd
;
91 cpu_data
[cpu
].udelay_val
= loops_per_jiffy
;
93 CPUMASK_SETB(cpu_online_map
, cpu
);
94 atomic_inc(&cpus_booted
);
97 printk("Slave cpu booted successfully \n");
98 *(volatile uint32_t *)(0xbb000a68) = 0x00000000;
99 *(volatile uint32_t *)(0xbb000a68) = 0x80000000;
101 while (*(volatile uint32_t *)(0xbb000a68) != 0x00000000);
106 void __init
smp_boot_cpus(void)
111 smp_num_cpus
= prom_setup_smp();
112 printk("Detected %d available CPUs \n", smp_num_cpus
);
114 init_new_context(current
, &init_mm
);
115 current
->processor
= 0;
116 cpu_data
[0].udelay_val
= loops_per_jiffy
;
117 cpu_data
[0].asid_cache
= ASID_FIRST_VERSION
;
118 CPUMASK_CLRALL(cpu_online_map
);
119 CPUMASK_SETB(cpu_online_map
, 0);
120 atomic_set(&cpus_booted
, 1); /* Master CPU is already booted... */
123 __cpu_number_map
[0] = 0;
124 __cpu_logical_map
[0] = 0;
127 * This loop attempts to compensate for "holes" in the CPU
128 * numbering. It's overkill, but general.
130 for (i
= 1; i
< smp_num_cpus
; ) {
131 struct task_struct
*p
;
134 printk("Starting CPU %d... \n", i
);
136 /* Spawn a new process normally. Grab a pointer to
137 its task struct so we can mess with it */
138 do_fork(CLONE_VM
|CLONE_PID
, 0, ®s
, 0);
140 p
= init_task
.prev_task
;
142 panic("failed fork for CPU %d", i
);
144 /* This is current for the second processor */
146 p
->cpus_runnable
= 1 << i
; /* we schedule the first task manually */
147 p
->thread
.reg31
= (unsigned long) start_secondary
;
149 del_from_runqueue(p
);
156 /* Iterate until we find a CPU that comes up */
158 retval
= prom_boot_secondary(cur_cpu
,
159 (unsigned long)p
+ KERNEL_STACK_SIZE
- 32,
162 } while (!retval
&& (cur_cpu
< NR_CPUS
));
164 __cpu_number_map
[cur_cpu
] = i
;
165 __cpu_logical_map
[i
] = cur_cpu
;
168 panic("CPU discovery disaster");
172 /* Local semaphore to both the CPUs */
174 *(volatile uint32_t *)(0xbb000a68) = 0x80000000;
175 while (*(volatile uint32_t *)(0xbb000a68) != 0x00000000);
177 smp_threads_ready
= 1;