Skip to content

Commit aca95fb

Browse files
paulusmackmaddy-kerneldev
authored andcommitted
powerpc/microwatt: Add SMP support
This adds support for Microwatt systems with more than one core, and updates the device tree for a 2-core version. The secondary CPUs are started and sent to spin in __secondary_hold very early on, in the platform probe function. The reason for doing this is so that they are there when smp_release_cpus() gets called, which is before the platform init_smp function or even the platform setup_arch function gets called. Note that having two CPUs in the device tree doesn't preclude operation with only one CPU. The SYSCON_CPU_CTRL register has a read-only field which indicates the number of CPU cores, so microwatt_init_smp() will only start as many CPU cores as are present in the system, and any extra CPU device-tree nodes will just be ignored. Signed-off-by: Paul Mackerras <paulus@ozlabs.org> Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com> Link: https://patch.msgid.link/Z5xt8aooKyXZv6Kf@thinks.paulus.ozlabs.org
1 parent 3d45a3d commit aca95fb

File tree

6 files changed

+124
-3
lines changed

6 files changed

+124
-3
lines changed

arch/powerpc/boot/dts/microwatt.dts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,36 @@
142142
ibm,mmu-lpid-bits = <12>;
143143
ibm,mmu-pid-bits = <20>;
144144
};
145+
146+
PowerPC,Microwatt@1 {
147+
i-cache-sets = <2>;
148+
ibm,dec-bits = <64>;
149+
reservation-granule-size = <64>;
150+
clock-frequency = <100000000>;
151+
timebase-frequency = <100000000>;
152+
i-tlb-sets = <1>;
153+
ibm,ppc-interrupt-server#s = <1>;
154+
i-cache-block-size = <64>;
155+
d-cache-block-size = <64>;
156+
d-cache-sets = <2>;
157+
i-tlb-size = <64>;
158+
cpu-version = <0x990000>;
159+
status = "okay";
160+
i-cache-size = <0x1000>;
161+
ibm,processor-radix-AP-encodings = <0x0c 0xa0000010 0x20000015 0x4000001e>;
162+
tlb-size = <0>;
163+
tlb-sets = <0>;
164+
device_type = "cpu";
165+
d-tlb-size = <128>;
166+
d-tlb-sets = <2>;
167+
reg = <1>;
168+
general-purpose;
169+
64-bit;
170+
d-cache-size = <0x1000>;
171+
ibm,chip-id = <0>;
172+
ibm,mmu-lpid-bits = <12>;
173+
ibm,mmu-pid-bits = <20>;
174+
};
145175
};
146176

147177
soc@c0000000 {
@@ -154,8 +184,8 @@
154184

155185
interrupt-controller@4000 {
156186
compatible = "openpower,xics-presentation", "ibm,ppc-xicp";
157-
ibm,interrupt-server-ranges = <0x0 0x1>;
158-
reg = <0x4000 0x100>;
187+
ibm,interrupt-server-ranges = <0x0 0x2>;
188+
reg = <0x4000 0x10 0x4010 0x10>;
159189
};
160190

161191
ICS: interrupt-controller@5000 {

arch/powerpc/platforms/microwatt/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0
22
config PPC_MICROWATT
3-
depends on PPC_BOOK3S_64 && !SMP
3+
depends on PPC_BOOK3S_64
44
bool "Microwatt SoC platform"
55
select PPC_XICS
66
select PPC_ICS_NATIVE
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
obj-y += setup.o rng.o
2+
obj-$(CONFIG_SMP) += smp.o

arch/powerpc/platforms/microwatt/microwatt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
#define _MICROWATT_H
44

55
void microwatt_rng_init(void);
6+
void microwatt_init_smp(void);
67

78
#endif /* _MICROWATT_H */

arch/powerpc/platforms/microwatt/setup.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ static int __init microwatt_populate(void)
2929
}
3030
machine_arch_initcall(microwatt, microwatt_populate);
3131

32+
static int __init microwatt_probe(void)
33+
{
34+
/* Main reason for having this is to start the other CPU(s) */
35+
if (IS_ENABLED(CONFIG_SMP))
36+
microwatt_init_smp();
37+
return 1;
38+
}
39+
3240
static void __init microwatt_setup_arch(void)
3341
{
3442
microwatt_rng_init();
@@ -45,6 +53,7 @@ static void microwatt_idle(void)
4553
define_machine(microwatt) {
4654
.name = "microwatt",
4755
.compatible = "microwatt-soc",
56+
.probe = microwatt_probe,
4857
.init_IRQ = microwatt_init_IRQ,
4958
.setup_arch = microwatt_setup_arch,
5059
.progress = udbg_progress,
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
3+
/*
4+
* SMP support functions for Microwatt
5+
* Copyright 2025 Paul Mackerras <paulus@ozlabs.org>
6+
*/
7+
8+
#include <linux/kernel.h>
9+
#include <linux/smp.h>
10+
#include <linux/io.h>
11+
#include <asm/early_ioremap.h>
12+
#include <asm/ppc-opcode.h>
13+
#include <asm/reg.h>
14+
#include <asm/smp.h>
15+
#include <asm/xics.h>
16+
17+
#include "microwatt.h"
18+
19+
static void __init microwatt_smp_probe(void)
20+
{
21+
xics_smp_probe();
22+
}
23+
24+
static void microwatt_smp_setup_cpu(int cpu)
25+
{
26+
if (cpu != 0)
27+
xics_setup_cpu();
28+
}
29+
30+
static struct smp_ops_t microwatt_smp_ops = {
31+
.probe = microwatt_smp_probe,
32+
.message_pass = NULL, /* Use smp_muxed_ipi_message_pass */
33+
.kick_cpu = smp_generic_kick_cpu,
34+
.setup_cpu = microwatt_smp_setup_cpu,
35+
};
36+
37+
/* XXX get from device tree */
38+
#define SYSCON_BASE 0xc0000000
39+
#define SYSCON_LENGTH 0x100
40+
41+
#define SYSCON_CPU_CTRL 0x58
42+
43+
void __init microwatt_init_smp(void)
44+
{
45+
volatile unsigned char __iomem *syscon;
46+
int ncpus;
47+
int timeout;
48+
49+
syscon = early_ioremap(SYSCON_BASE, SYSCON_LENGTH);
50+
if (syscon == NULL) {
51+
pr_err("Failed to map SYSCON\n");
52+
return;
53+
}
54+
ncpus = (readl(syscon + SYSCON_CPU_CTRL) >> 8) & 0xff;
55+
if (ncpus < 2)
56+
goto out;
57+
58+
smp_ops = &microwatt_smp_ops;
59+
60+
/*
61+
* Write two instructions at location 0:
62+
* mfspr r3, PIR
63+
* b __secondary_hold
64+
*/
65+
*(unsigned int *)KERNELBASE = PPC_RAW_MFSPR(3, SPRN_PIR);
66+
*(unsigned int *)(KERNELBASE+4) = PPC_RAW_BRANCH(&__secondary_hold - (char *)(KERNELBASE+4));
67+
68+
/* enable the other CPUs, they start at location 0 */
69+
writel((1ul << ncpus) - 1, syscon + SYSCON_CPU_CTRL);
70+
71+
timeout = 10000;
72+
while (!__secondary_hold_acknowledge) {
73+
if (--timeout == 0)
74+
break;
75+
barrier();
76+
}
77+
78+
out:
79+
early_iounmap((void *)syscon, SYSCON_LENGTH);
80+
}

0 commit comments

Comments
 (0)