From 0924ac3b7dee1e12b6583c79cc869ec92ddc0c72 Mon Sep 17 00:00:00 2001
From: Luis Gerhorst <privat@luisgerhorst.de>
Date: Wed, 16 Dec 2020 15:20:46 +0100
Subject: [PATCH] Compile with CONFIG_SMP

---
 arch/arm/core/aarch64/CMakeLists.txt          |  1 +
 arch/arm/core/aarch64/cpu_smp.c               | 38 +++++++++++++++++++
 arch/arm/core/aarch64/macro_priv.inc          | 22 ++++++++---
 arch/arm/core/offsets/offsets_aarch64.c       |  4 ++
 boards/arm/qemu_raspi3/qemu_raspi3.dts        | 21 +++++++---
 boards/arm/qemu_raspi3/qemu_raspi3_defconfig  |  4 ++
 drivers/timer/Kconfig                         |  3 +-
 drivers/timer/arm_arch_timer.c                |  7 ++++
 drivers/timer/bcm2835_arm_timer.c             |  2 +
 .../brcm,bcm2835-armctrl-ic.yaml              | 10 ++---
 .../brcm,bcm2835-l1-intc.yaml                 | 21 ++++++++++
 include/arch/arm/aarch64/asm_inline_gcc.h     | 17 +++++++++
 12 files changed, 129 insertions(+), 21 deletions(-)
 create mode 100644 arch/arm/core/aarch64/cpu_smp.c
 create mode 100644 dts/bindings/interrupt-controller/brcm,bcm2835-l1-intc.yaml

diff --git a/arch/arm/core/aarch64/CMakeLists.txt b/arch/arm/core/aarch64/CMakeLists.txt
index 57ad9a8593d..b336145dfa1 100644
--- a/arch/arm/core/aarch64/CMakeLists.txt
+++ b/arch/arm/core/aarch64/CMakeLists.txt
@@ -31,3 +31,4 @@ zephyr_library_sources_ifdef(CONFIG_GEN_SW_ISR_TABLE isr_wrapper.S)
 zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c)
 zephyr_library_sources_ifdef(CONFIG_ARM_MMU arm_mmu.c)
 zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE ../common/tls.c)
+zephyr_library_sources_ifdef(CONFIG_SMP cpu_smp.c)
diff --git a/arch/arm/core/aarch64/cpu_smp.c b/arch/arm/core/aarch64/cpu_smp.c
new file mode 100644
index 00000000000..a8b2ec2a254
--- /dev/null
+++ b/arch/arm/core/aarch64/cpu_smp.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 Intel Corporation
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <kernel.h>
+#include <kernel_arch_data.h>
+#include <kernel_arch_func.h>
+#include <kernel_structs.h>
+#include <kernel_internal.h>
+
+static ALWAYS_INLINE void __SEV(void)
+{
+	__asm__ volatile ("sev" : : : "memory");
+}
+
+/* References:
+ * - https://github.com/torvalds/linux/commit/08e875c16a16c950e1e6d85755df5f3440844675
+ * - stubs/src.armv7/kernel/boot/startup.S
+ *
+ * */
+void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz,
+		    arch_cpustart_t fn, void *arg)
+{
+	printk("%s\n", __func__);
+	/* e.g.
+	   #define ARM7_MBOX_OFF_C1_MB3 0x9C
+	   #define ARM7_MBOX_OFF_C2_MB3 0xAC
+	   #define ARM7_MBOX_OFF_C3_MB3 0xBC */
+	/* intptr_t cpu_mbox_addr = ARM7_MBOX_BASE + 0x8C + (intptr_t) cpu_num * 0x10; */
+
+	/* = (arch_cpustart_t *) cpu_mbox_addr; */
+	/* *cpu_mbox = fn; */
+
+	// synchronise and wake up other cores
+	/* __DSB(); */
+	/* __SEV(); */
+}
diff --git a/arch/arm/core/aarch64/macro_priv.inc b/arch/arm/core/aarch64/macro_priv.inc
index f941eced636..1a8b001002d 100644
--- a/arch/arm/core/aarch64/macro_priv.inc
+++ b/arch/arm/core/aarch64/macro_priv.inc
@@ -101,6 +101,15 @@
 	eret
 .endm
 
+.macro arch_curr_cpu xreg0, xreg1
+    mrs \xreg1, mpidr_el1
+    and \xreg1, \xreg1, #0xFF
+    mov \xreg0, #__cpu_t_SIZEOF
+    mul \xreg1, \xreg1, \xreg0
+    ldr \xreg0, =_kernel
+    add \xreg0, \xreg0, \xreg1	
+.endm
+
 /**
  * @brief Increment nested counter
  *
@@ -108,10 +117,10 @@
  */
 
 .macro inc_nest_counter xreg0, xreg1
-	ldr	\xreg0, =_kernel
-	ldr	\xreg1, [\xreg0, #_kernel_offset_to_nested]
+    arch_curr_cpu \xreg0, \xreg1
+	ldr	\xreg1, [\xreg0, #___cpu_t_nested_OFFSET]
 	add	\xreg1, \xreg1, #1
-	str	\xreg1, [\xreg0, #_kernel_offset_to_nested]
+	str	\xreg1, [\xreg0, #___cpu_t_nested_OFFSET]
 .endm
 
 /**
@@ -121,10 +130,11 @@
  */
 
 .macro dec_nest_counter xreg0, xreg1
-	ldr	\xreg0, =_kernel
-	ldr	\xreg1, [\xreg0, #_kernel_offset_to_nested]
+mrs \xreg1, mpidr_el1
+    arch_curr_cpu \xreg0, \xreg1
+	ldr	\xreg1, [\xreg0, #___cpu_t_nested_OFFSET]
 	sub	\xreg1, \xreg1, #1
-	str	\xreg1, [\xreg0, #_kernel_offset_to_nested]
+	str	\xreg1, [\xreg0, #___cpu_t_nested_OFFSET]
 .endm
 
 #endif /* _ASMLANGUAGE */
diff --git a/arch/arm/core/offsets/offsets_aarch64.c b/arch/arm/core/offsets/offsets_aarch64.c
index 4e75c78038b..f06582a8216 100644
--- a/arch/arm/core/offsets/offsets_aarch64.c
+++ b/arch/arm/core/offsets/offsets_aarch64.c
@@ -29,4 +29,8 @@
 #include <kernel_arch_data.h>
 #include <kernel_offsets.h>
 
+#ifdef CONFIG_SMP
+GEN_ABSOLUTE_SYM(__cpu_t_SIZEOF, sizeof(_cpu_t));
+#endif
+
 #endif /* _ARM_OFFSETS_INC_ */
diff --git a/boards/arm/qemu_raspi3/qemu_raspi3.dts b/boards/arm/qemu_raspi3/qemu_raspi3.dts
index 475ba056d50..acba1c26b18 100644
--- a/boards/arm/qemu_raspi3/qemu_raspi3.dts
+++ b/boards/arm/qemu_raspi3/qemu_raspi3.dts
@@ -48,23 +48,30 @@
 			compatible = "brcm,bcm2835-armctrl-ic";
 			reg = <0x3f00b200 0x200>;
 			interrupt-controller;
-			#interrupt-cells = <2>;
+			#interrupt-cells = <3>;
             label = "intc";
 		};
 
         local_intc: local_intc@40000000 {
-			compatible = "brcm,bcm2836-l1-intc";
+			compatible = "brcm,bcm2835-l1-intc";
 			reg = <0x40000000 0x100>;
 			interrupt-controller;
-			#interrupt-cells = <2>;
-			interrupt-parent = <&local_intc>;
+			#interrupt-cells = <3>;
+            label = "l1-intc";
 		};
 
+        timer {
+		    compatible = "arm,arm-timer";
+		    interrupt-parent = <&local_intc>;
+		    interrupts = <0 0 0>, <1 0 0>, <2 0 0>, <3 0 0>; /* CNTPSIRQ, CNTPNSIRQ, CNTHPIRQ, CNTVIRQ */
+		    label = "arch_timer";
+	    };
+
         /* https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson03/rpi-os.md#timer-initialization */
 		timer@3f003000 {
 			compatible = "brcm,bcm2835-system-timer";
 			reg = <0x3f003000 0x20>;
-			interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
+			interrupts = <0 0 0>, <1 0 0>, <2 0 0>, <3 0 0>;
 			/* This could be a reference to BCM2835_CLOCK_TIMER,
 			 * but we don't have the driver using the common clock
 			 * support yet.
@@ -72,10 +79,12 @@
 			clock-frequency = <1000000>; /* 1MHz */
 		};
 
+        /* Page 196 in the "BCM2837 ARM Peripherals manual" https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf */
+        /* TODO: This is likely not required. We just need timer@3f003000 for the system clock and armv7-timer for the timer ticks. */
         timer@3f00b000 {
 			compatible = "brcm,bcm2835-arm-timer";
 			reg = <0x3f00b000 0x1000>;
-			interrupts = <1 64>;
+			interrupts = <64 0 0>;
 			clock-frequency = <1000000>; /* 1MHz */
 		};
 
diff --git a/boards/arm/qemu_raspi3/qemu_raspi3_defconfig b/boards/arm/qemu_raspi3/qemu_raspi3_defconfig
index 4701bd1ce25..5f787cd68f1 100644
--- a/boards/arm/qemu_raspi3/qemu_raspi3_defconfig
+++ b/boards/arm/qemu_raspi3/qemu_raspi3_defconfig
@@ -26,3 +26,7 @@ CONFIG_UART_RASPI3_MINI=y
 CONFIG_QEMU_ICOUNT=n
 # CONFIG_BOOTLOADER_SRAM_SIZE=512
 CONFIG_LOG=y
+
+CONFIG_SMP=y
+CONFIG_MP_NUM_CPUS=4
+CONFIG_ARM_ARCH_TIMER=y
\ No newline at end of file
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index a6fd5af5f0f..10815723e91 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -113,7 +113,6 @@ config ARCV2_TIMER_IRQ_PRIORITY
 
 config ARM_ARCH_TIMER
 	bool "ARM architected timer"
-	depends on GIC
 	select TICKLESS_CAPABLE
 	help
 	  This module implements a kernel device driver for the ARM architected
@@ -307,7 +306,7 @@ config BCM2835_SYSTEM_TIMER
 
 config BCM2835_ARM_TIMER
 	bool "BCM2835 and BCM2837 ARM Timer"
-	default y
+	default n
 	depends on !TICKLESS_IDLE
 	depends on SOC_QEMU_RASPI3
 	help
diff --git a/drivers/timer/arm_arch_timer.c b/drivers/timer/arm_arch_timer.c
index bbf95b30c06..5b186c5ad08 100644
--- a/drivers/timer/arm_arch_timer.c
+++ b/drivers/timer/arm_arch_timer.c
@@ -106,3 +106,10 @@ uint32_t z_timer_cycle_get_32(void)
 {
 	return (uint32_t)arm_arch_timer_count();
 }
+
+#if defined(CONFIG_SMP) && CONFIG_MP_NUM_CPUS > 1
+void smp_timer_init(void)
+{
+	/* Nothing to be executed on each individual cpu. */
+}
+#endif
diff --git a/drivers/timer/bcm2835_arm_timer.c b/drivers/timer/bcm2835_arm_timer.c
index 841b7390e9b..ccc34fe7d3d 100644
--- a/drivers/timer/bcm2835_arm_timer.c
+++ b/drivers/timer/bcm2835_arm_timer.c
@@ -11,6 +11,7 @@
 #include <device.h>
 #include <irq.h>
 #include <spinlock.h>
+#include <drivers/timer/system_timer.h>
 
 #define ARM_TIMER_BASE DT_INST_REG_ADDR(0)
 
@@ -70,4 +71,5 @@ int z_clock_driver_init(const struct device *device)
 	// system timer.
 	put32(ARM_TIMER_LOAD, k_ticks_to_cyc_floor32(1));
 	put32(ARM_TIMER_CTRL, CTRL_ENABLE | CTRL_INT_ENABLE | CTRL_23BIT);
+	return 0;
 }
diff --git a/dts/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.yaml b/dts/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.yaml
index 4c385ae66fe..93386a80ec1 100644
--- a/dts/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.yaml
+++ b/dts/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.yaml
@@ -14,12 +14,8 @@ properties:
     label:
       required: true
 
-# The 1st cell is the interrupt bank; 0 for interrupts in the "IRQ basic
-# pending" register, or 1/2 respectively for interrupts in the "IRQ pending
-# 1/2" register.
-# 
-# The 2nd cell contains the interrupt number within the bank. Valid values
-# are 0..7 for bank 0, and 0..31 for bank 1.
+# GIC-compatible to allow reuse of arm,arm-timer. flags and priority are always 0.
 interrupt-cells:
   - irq
-  - number
+  - flags
+  - priority
diff --git a/dts/bindings/interrupt-controller/brcm,bcm2835-l1-intc.yaml b/dts/bindings/interrupt-controller/brcm,bcm2835-l1-intc.yaml
new file mode 100644
index 00000000000..917b9814136
--- /dev/null
+++ b/dts/bindings/interrupt-controller/brcm,bcm2835-l1-intc.yaml
@@ -0,0 +1,21 @@
+# Copyright (c) 2018 Marvell
+# SPDX-License-Identifier: Apache-2.0
+
+description: Interrupt Controller
+
+compatible: "brcm,bcm2835-l1-intc"
+
+include: base.yaml
+
+properties:
+    reg:
+      required: true
+
+    label:
+      required: true
+
+# GIC-compatible to allow reuse of arm,arm-timer. flags and priority are always 0.
+interrupt-cells:
+  - irq
+  - flags
+  - priority
diff --git a/include/arch/arm/aarch64/asm_inline_gcc.h b/include/arch/arm/aarch64/asm_inline_gcc.h
index f8614880c3e..d17f1979d67 100644
--- a/include/arch/arm/aarch64/asm_inline_gcc.h
+++ b/include/arch/arm/aarch64/asm_inline_gcc.h
@@ -18,6 +18,7 @@
 
 #include <arch/arm/aarch64/cpu.h>
 #include <zephyr/types.h>
+#include <kernel_structs.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -71,6 +72,22 @@ static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key)
 	return (key & DAIF_IRQ) == 0;
 }
 
+static ALWAYS_INLINE struct _cpu *arch_curr_cpu(void)
+{
+#ifdef CONFIG_SMP
+	unsigned int k = arch_irq_lock();
+
+	unsigned long mpid = read_sysreg(mpidr_el1);
+	struct _cpu *ret = &_kernel.cpus[mpid & 0xff];
+
+	arch_irq_unlock(k);
+
+	return ret;
+#else
+	return &_kernel.cpus[0];
+#endif
+}
+
 #ifdef __cplusplus
 }
 #endif
-- 
GitLab