Skip to content

Commit

Permalink
powerpc/microwatt: Add SMP support
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Paul Mackerras authored and Madhavan Srinivasan committed Feb 26, 2025
1 parent 3d45a3d commit aca95fb
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 3 deletions.
34 changes: 32 additions & 2 deletions arch/powerpc/boot/dts/microwatt.dts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,36 @@
ibm,mmu-lpid-bits = <12>;
ibm,mmu-pid-bits = <20>;
};

PowerPC,Microwatt@1 {
i-cache-sets = <2>;
ibm,dec-bits = <64>;
reservation-granule-size = <64>;
clock-frequency = <100000000>;
timebase-frequency = <100000000>;
i-tlb-sets = <1>;
ibm,ppc-interrupt-server#s = <1>;
i-cache-block-size = <64>;
d-cache-block-size = <64>;
d-cache-sets = <2>;
i-tlb-size = <64>;
cpu-version = <0x990000>;
status = "okay";
i-cache-size = <0x1000>;
ibm,processor-radix-AP-encodings = <0x0c 0xa0000010 0x20000015 0x4000001e>;
tlb-size = <0>;
tlb-sets = <0>;
device_type = "cpu";
d-tlb-size = <128>;
d-tlb-sets = <2>;
reg = <1>;
general-purpose;
64-bit;
d-cache-size = <0x1000>;
ibm,chip-id = <0>;
ibm,mmu-lpid-bits = <12>;
ibm,mmu-pid-bits = <20>;
};
};

soc@c0000000 {
Expand All @@ -154,8 +184,8 @@

interrupt-controller@4000 {
compatible = "openpower,xics-presentation", "ibm,ppc-xicp";
ibm,interrupt-server-ranges = <0x0 0x1>;
reg = <0x4000 0x100>;
ibm,interrupt-server-ranges = <0x0 0x2>;
reg = <0x4000 0x10 0x4010 0x10>;
};

ICS: interrupt-controller@5000 {
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/platforms/microwatt/Kconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
config PPC_MICROWATT
depends on PPC_BOOK3S_64 && !SMP
depends on PPC_BOOK3S_64
bool "Microwatt SoC platform"
select PPC_XICS
select PPC_ICS_NATIVE
Expand Down
1 change: 1 addition & 0 deletions arch/powerpc/platforms/microwatt/Makefile
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
obj-y += setup.o rng.o
obj-$(CONFIG_SMP) += smp.o
1 change: 1 addition & 0 deletions arch/powerpc/platforms/microwatt/microwatt.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
#define _MICROWATT_H

void microwatt_rng_init(void);
void microwatt_init_smp(void);

#endif /* _MICROWATT_H */
9 changes: 9 additions & 0 deletions arch/powerpc/platforms/microwatt/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ static int __init microwatt_populate(void)
}
machine_arch_initcall(microwatt, microwatt_populate);

static int __init microwatt_probe(void)
{
/* Main reason for having this is to start the other CPU(s) */
if (IS_ENABLED(CONFIG_SMP))
microwatt_init_smp();
return 1;
}

static void __init microwatt_setup_arch(void)
{
microwatt_rng_init();
Expand All @@ -45,6 +53,7 @@ static void microwatt_idle(void)
define_machine(microwatt) {
.name = "microwatt",
.compatible = "microwatt-soc",
.probe = microwatt_probe,
.init_IRQ = microwatt_init_IRQ,
.setup_arch = microwatt_setup_arch,
.progress = udbg_progress,
Expand Down
80 changes: 80 additions & 0 deletions arch/powerpc/platforms/microwatt/smp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// SPDX-License-Identifier: GPL-2.0-or-later

/*
* SMP support functions for Microwatt
* Copyright 2025 Paul Mackerras <paulus@ozlabs.org>
*/

#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/io.h>
#include <asm/early_ioremap.h>
#include <asm/ppc-opcode.h>
#include <asm/reg.h>
#include <asm/smp.h>
#include <asm/xics.h>

#include "microwatt.h"

static void __init microwatt_smp_probe(void)
{
xics_smp_probe();
}

static void microwatt_smp_setup_cpu(int cpu)
{
if (cpu != 0)
xics_setup_cpu();
}

static struct smp_ops_t microwatt_smp_ops = {
.probe = microwatt_smp_probe,
.message_pass = NULL, /* Use smp_muxed_ipi_message_pass */
.kick_cpu = smp_generic_kick_cpu,
.setup_cpu = microwatt_smp_setup_cpu,
};

/* XXX get from device tree */
#define SYSCON_BASE 0xc0000000
#define SYSCON_LENGTH 0x100

#define SYSCON_CPU_CTRL 0x58

void __init microwatt_init_smp(void)
{
volatile unsigned char __iomem *syscon;
int ncpus;
int timeout;

syscon = early_ioremap(SYSCON_BASE, SYSCON_LENGTH);
if (syscon == NULL) {
pr_err("Failed to map SYSCON\n");
return;
}
ncpus = (readl(syscon + SYSCON_CPU_CTRL) >> 8) & 0xff;
if (ncpus < 2)
goto out;

smp_ops = &microwatt_smp_ops;

/*
* Write two instructions at location 0:
* mfspr r3, PIR
* b __secondary_hold
*/
*(unsigned int *)KERNELBASE = PPC_RAW_MFSPR(3, SPRN_PIR);
*(unsigned int *)(KERNELBASE+4) = PPC_RAW_BRANCH(&__secondary_hold - (char *)(KERNELBASE+4));

/* enable the other CPUs, they start at location 0 */
writel((1ul << ncpus) - 1, syscon + SYSCON_CPU_CTRL);

timeout = 10000;
while (!__secondary_hold_acknowledge) {
if (--timeout == 0)
break;
barrier();
}

out:
early_iounmap((void *)syscon, SYSCON_LENGTH);
}

0 comments on commit aca95fb

Please sign in to comment.