mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 03:44:45 +01:00
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
This commit is contained in:
parent
3d45a3d0d2
commit
aca95fb6bb
6 changed files with 124 additions and 3 deletions
|
|
@ -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 {
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
obj-y += setup.o rng.o
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@
|
|||
#define _MICROWATT_H
|
||||
|
||||
void microwatt_rng_init(void);
|
||||
void microwatt_init_smp(void);
|
||||
|
||||
#endif /* _MICROWATT_H */
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
80
arch/powerpc/platforms/microwatt/smp.c
Normal file
80
arch/powerpc/platforms/microwatt/smp.c
Normal file
|
|
@ -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 = µwatt_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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue