]>
Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 LT |
2 | /* |
3 | * Copyright (C) 2001, 2002, 2003 Broadcom Corporation | |
1da177e4 LT |
4 | */ |
5 | ||
6 | #include <linux/init.h> | |
7 | #include <linux/delay.h> | |
8 | #include <linux/interrupt.h> | |
9 | #include <linux/smp.h> | |
10 | #include <linux/kernel_stat.h> | |
f3ac6067 | 11 | #include <linux/sched/task_stack.h> |
1da177e4 LT |
12 | |
13 | #include <asm/mmu_context.h> | |
14 | #include <asm/io.h> | |
87353d8a | 15 | #include <asm/fw/cfe/cfe_api.h> |
1da177e4 LT |
16 | #include <asm/sibyte/sb1250.h> |
17 | #include <asm/sibyte/sb1250_regs.h> | |
18 | #include <asm/sibyte/sb1250_int.h> | |
19 | ||
20 | static void *mailbox_set_regs[] = { | |
65bda1a9 MR |
21 | IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU), |
22 | IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_SET_CPU) | |
1da177e4 LT |
23 | }; |
24 | ||
25 | static void *mailbox_clear_regs[] = { | |
65bda1a9 MR |
26 | IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU), |
27 | IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CLR_CPU) | |
1da177e4 LT |
28 | }; |
29 | ||
30 | static void *mailbox_regs[] = { | |
65bda1a9 MR |
31 | IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU), |
32 | IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CPU) | |
1da177e4 LT |
33 | }; |
34 | ||
35 | /* | |
36 | * SMP init and finish on secondary CPUs | |
37 | */ | |
078a55fc | 38 | void sb1250_smp_init(void) |
1da177e4 LT |
39 | { |
40 | unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | | |
41 | STATUSF_IP1 | STATUSF_IP0; | |
42 | ||
43 | /* Set interrupt mask, but don't enable */ | |
44 | change_c0_status(ST0_IM, imask); | |
45 | } | |
46 | ||
87353d8a RB |
47 | /* |
48 | * These are routines for dealing with the sb1250 smp capabilities | |
49 | * independent of board/firmware | |
50 | */ | |
51 | ||
52 | /* | |
53 | * Simple enough; everything is set up, so just poke the appropriate mailbox | |
54 | * register, and we should be set | |
55 | */ | |
56 | static void sb1250_send_ipi_single(int cpu, unsigned int action) | |
57 | { | |
58 | __raw_writeq((((u64)action) << 48), mailbox_set_regs[cpu]); | |
59 | } | |
60 | ||
48a048fe RR |
61 | static inline void sb1250_send_ipi_mask(const struct cpumask *mask, |
62 | unsigned int action) | |
87353d8a RB |
63 | { |
64 | unsigned int i; | |
65 | ||
48a048fe | 66 | for_each_cpu(i, mask) |
87353d8a RB |
67 | sb1250_send_ipi_single(i, action); |
68 | } | |
69 | ||
70 | /* | |
71 | * Code to run on secondary just after probing the CPU | |
72 | */ | |
078a55fc | 73 | static void sb1250_init_secondary(void) |
87353d8a RB |
74 | { |
75 | extern void sb1250_smp_init(void); | |
76 | ||
77 | sb1250_smp_init(); | |
78 | } | |
79 | ||
80 | /* | |
81 | * Do any tidying up before marking online and running the idle | |
82 | * loop | |
83 | */ | |
078a55fc | 84 | static void sb1250_smp_finish(void) |
1da177e4 | 85 | { |
d527eef5 RB |
86 | extern void sb1250_clockevent_init(void); |
87 | ||
88 | sb1250_clockevent_init(); | |
1da177e4 LT |
89 | local_irq_enable(); |
90 | } | |
91 | ||
1da177e4 | 92 | /* |
87353d8a RB |
93 | * Setup the PC, SP, and GP of a secondary processor and start it |
94 | * running! | |
1da177e4 | 95 | */ |
d595d423 | 96 | static int sb1250_boot_secondary(int cpu, struct task_struct *idle) |
1da177e4 | 97 | { |
87353d8a RB |
98 | int retval; |
99 | ||
100 | retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap, | |
101 | __KSTK_TOS(idle), | |
102 | (unsigned long)task_thread_info(idle), 0); | |
103 | if (retval != 0) | |
104 | printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval); | |
d595d423 | 105 | return retval; |
1da177e4 LT |
106 | } |
107 | ||
87353d8a RB |
108 | /* |
109 | * Use CFE to find out how many CPUs are available, setting up | |
0b5f9c00 | 110 | * cpu_possible_mask and the logical/physical mappings. |
87353d8a RB |
111 | * XXXKW will the boot CPU ever not be physical 0? |
112 | * | |
113 | * Common setup before any secondaries are started | |
114 | */ | |
115 | static void __init sb1250_smp_setup(void) | |
116 | { | |
117 | int i, num; | |
118 | ||
0b5f9c00 | 119 | init_cpu_possible(cpumask_of(0)); |
87353d8a RB |
120 | __cpu_number_map[0] = 0; |
121 | __cpu_logical_map[0] = 0; | |
122 | ||
123 | for (i = 1, num = 0; i < NR_CPUS; i++) { | |
124 | if (cfe_cpu_stop(i) == 0) { | |
0b5f9c00 | 125 | set_cpu_possible(i, true); |
87353d8a RB |
126 | __cpu_number_map[i] = ++num; |
127 | __cpu_logical_map[num] = i; | |
128 | } | |
129 | } | |
130 | printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num); | |
131 | } | |
132 | ||
133 | static void __init sb1250_prepare_cpus(unsigned int max_cpus) | |
134 | { | |
135 | } | |
136 | ||
ff2c8252 | 137 | const struct plat_smp_ops sb_smp_ops = { |
87353d8a RB |
138 | .send_ipi_single = sb1250_send_ipi_single, |
139 | .send_ipi_mask = sb1250_send_ipi_mask, | |
140 | .init_secondary = sb1250_init_secondary, | |
141 | .smp_finish = sb1250_smp_finish, | |
87353d8a RB |
142 | .boot_secondary = sb1250_boot_secondary, |
143 | .smp_setup = sb1250_smp_setup, | |
144 | .prepare_cpus = sb1250_prepare_cpus, | |
145 | }; | |
146 | ||
937a8015 | 147 | void sb1250_mailbox_interrupt(void) |
1da177e4 LT |
148 | { |
149 | int cpu = smp_processor_id(); | |
d2287f5e | 150 | int irq = K_INT_MBOX_0; |
1da177e4 LT |
151 | unsigned int action; |
152 | ||
310ff2c8 | 153 | kstat_incr_irq_this_cpu(irq); |
1da177e4 | 154 | /* Load the mailbox register to figure out what we're supposed to do */ |
65bda1a9 | 155 | action = (____raw_readq(mailbox_regs[cpu]) >> 48) & 0xffff; |
1da177e4 LT |
156 | |
157 | /* Clear the mailbox to clear the interrupt */ | |
65bda1a9 | 158 | ____raw_writeq(((u64)action) << 48, mailbox_clear_regs[cpu]); |
1da177e4 | 159 | |
184748cc PZ |
160 | if (action & SMP_RESCHEDULE_YOURSELF) |
161 | scheduler_ipi(); | |
1da177e4 | 162 | |
4ace6139 AS |
163 | if (action & SMP_CALL_FUNCTION) { |
164 | irq_enter(); | |
165 | generic_smp_call_function_interrupt(); | |
166 | irq_exit(); | |
167 | } | |
1da177e4 | 168 | } |