Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/pmc-sierra/yosemite/smp.c
15118 views
1
#include <linux/linkage.h>
2
#include <linux/sched.h>
3
#include <linux/smp.h>
4
5
#include <asm/pmon.h>
6
#include <asm/titan_dep.h>
7
#include <asm/time.h>
8
9
#define LAUNCHSTACK_SIZE 256
10
11
static __cpuinitdata arch_spinlock_t launch_lock = __ARCH_SPIN_LOCK_UNLOCKED;
12
13
static unsigned long secondary_sp __cpuinitdata;
14
static unsigned long secondary_gp __cpuinitdata;
15
16
static unsigned char launchstack[LAUNCHSTACK_SIZE] __initdata
17
__attribute__((aligned(2 * sizeof(long))));
18
19
static void __init prom_smp_bootstrap(void)
20
{
21
local_irq_disable();
22
23
while (arch_spin_is_locked(&launch_lock));
24
25
__asm__ __volatile__(
26
" move $sp, %0 \n"
27
" move $gp, %1 \n"
28
" j smp_bootstrap \n"
29
:
30
: "r" (secondary_sp), "r" (secondary_gp));
31
}
32
33
/*
34
* PMON is a fragile beast. It'll blow up once the mappings it's littering
35
* right into the middle of KSEG3 are blown away so we have to grab the slave
36
* core early and keep it in a waiting loop.
37
*/
38
void __init prom_grab_secondary(void)
39
{
40
arch_spin_lock(&launch_lock);
41
42
pmon_cpustart(1, &prom_smp_bootstrap,
43
launchstack + LAUNCHSTACK_SIZE, 0);
44
}
45
46
void titan_mailbox_irq(void)
47
{
48
int cpu = smp_processor_id();
49
unsigned long status;
50
51
switch (cpu) {
52
case 0:
53
status = OCD_READ(RM9000x2_OCD_INTP0STATUS3);
54
OCD_WRITE(RM9000x2_OCD_INTP0CLEAR3, status);
55
56
if (status & 0x2)
57
smp_call_function_interrupt();
58
if (status & 0x4)
59
scheduler_ipi();
60
break;
61
62
case 1:
63
status = OCD_READ(RM9000x2_OCD_INTP1STATUS3);
64
OCD_WRITE(RM9000x2_OCD_INTP1CLEAR3, status);
65
66
if (status & 0x2)
67
smp_call_function_interrupt();
68
if (status & 0x4)
69
scheduler_ipi();
70
break;
71
}
72
}
73
74
/*
75
* Send inter-processor interrupt
76
*/
77
static void yos_send_ipi_single(int cpu, unsigned int action)
78
{
79
/*
80
* Generate an INTMSG so that it can be sent over to the
81
* destination CPU. The INTMSG will put the STATUS bits
82
* based on the action desired. An alternative strategy
83
* is to write to the Interrupt Set register, read the
84
* Interrupt Status register and clear the Interrupt
85
* Clear register. The latter is preffered.
86
*/
87
switch (action) {
88
case SMP_RESCHEDULE_YOURSELF:
89
if (cpu == 1)
90
OCD_WRITE(RM9000x2_OCD_INTP1SET3, 4);
91
else
92
OCD_WRITE(RM9000x2_OCD_INTP0SET3, 4);
93
break;
94
95
case SMP_CALL_FUNCTION:
96
if (cpu == 1)
97
OCD_WRITE(RM9000x2_OCD_INTP1SET3, 2);
98
else
99
OCD_WRITE(RM9000x2_OCD_INTP0SET3, 2);
100
break;
101
}
102
}
103
104
static void yos_send_ipi_mask(const struct cpumask *mask, unsigned int action)
105
{
106
unsigned int i;
107
108
for_each_cpu(i, mask)
109
yos_send_ipi_single(i, action);
110
}
111
112
/*
113
* After we've done initial boot, this function is called to allow the
114
* board code to clean up state, if needed
115
*/
116
static void __cpuinit yos_init_secondary(void)
117
{
118
set_c0_status(ST0_CO | ST0_IE | ST0_IM);
119
}
120
121
static void __cpuinit yos_smp_finish(void)
122
{
123
}
124
125
/* Hook for after all CPUs are online */
126
static void yos_cpus_done(void)
127
{
128
}
129
130
/*
131
* Firmware CPU startup hook
132
* Complicated by PMON's weird interface which tries to minimic the UNIX fork.
133
* It launches the next * available CPU and copies some information on the
134
* stack so the first thing we do is throw away that stuff and load useful
135
* values into the registers ...
136
*/
137
static void __cpuinit yos_boot_secondary(int cpu, struct task_struct *idle)
138
{
139
unsigned long gp = (unsigned long) task_thread_info(idle);
140
unsigned long sp = __KSTK_TOS(idle);
141
142
secondary_sp = sp;
143
secondary_gp = gp;
144
145
arch_spin_unlock(&launch_lock);
146
}
147
148
/*
149
* Detect available CPUs, populate cpu_possible_map before smp_init
150
*
151
* We don't want to start the secondary CPU yet nor do we have a nice probing
152
* feature in PMON so we just assume presence of the secondary core.
153
*/
154
static void __init yos_smp_setup(void)
155
{
156
int i;
157
158
cpus_clear(cpu_possible_map);
159
160
for (i = 0; i < 2; i++) {
161
cpu_set(i, cpu_possible_map);
162
__cpu_number_map[i] = i;
163
__cpu_logical_map[i] = i;
164
}
165
}
166
167
static void __init yos_prepare_cpus(unsigned int max_cpus)
168
{
169
/*
170
* Be paranoid. Enable the IPI only if we're really about to go SMP.
171
*/
172
if (cpus_weight(cpu_possible_map))
173
set_c0_status(STATUSF_IP5);
174
}
175
176
struct plat_smp_ops yos_smp_ops = {
177
.send_ipi_single = yos_send_ipi_single,
178
.send_ipi_mask = yos_send_ipi_mask,
179
.init_secondary = yos_init_secondary,
180
.smp_finish = yos_smp_finish,
181
.cpus_done = yos_cpus_done,
182
.boot_secondary = yos_boot_secondary,
183
.smp_setup = yos_smp_setup,
184
.prepare_cpus = yos_prepare_cpus,
185
};
186
187