Linux clock framework development
 help / color / mirror / Atom feed
* [PATCH v6 0/4] MIPS: CI20: Enable SMP with two CPUs
@ 2026-11-13 19:08 Florian Fainelli
  2026-11-13 19:08 ` [PATCH v6 1/4] clk: ingenic: Poll JZ4780 CPU1 power status atomically Florian Fainelli
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Florian Fainelli @ 2026-11-13 19:08 UTC (permalink / raw)
  To: linux-mips
  Cc: Florian Fainelli, Thomas Bogendoerfer, Paul Burton, Paul Cercueil,
	Stephen Boyd, Brian Masney, Jerome Brunet,
	周琰杰 (Zhou Yanjie), Jiaxun Yang, open list,
	open list:COMMON CLK FRAMEWORK, hns, paul

This patch series resurrects SMP support for the CI20 board. This was
submitted back in 2020 by Zhou Yanjie.

Changes in v6:

• Added missing Signed-off-by tag to patch #2

Changes in v5:

• Added changelog per-patch
• Split the generic IPI setup check
• Added comments explaining both need_resched()
• Removed void Reviewed/Tested-by tags

Changes in v4:

• Enable the secondary CPU clock outside the raw spinlock
• Mark enumerated CPUs present and assign hardware core IDs
• Skip generic IPI allocation when the platform supplies both IPI callbacks
• Fix generic 64-bit builds using CKSEG aliases and pointer-sized assembly macros
• Reject unsupported CPU offlining with -EOPNOTSUPP
• Restrict the XBurst SMP idle handler to multicore systems and recheck
  pending interrupts after flushing the cache

Changes in v3:

• Align the second line of the readl_poll_timeout_atomic() per Brian's
  feedback
• Collected Paul's R-b and T-b tags

Changes in v2:

• Moved SMP sources to arch/mips/ingenic/ and the header to arch/mips/include/asm/
• Removed CONFIG_MIPS_INGENIC_SMP, using CONFIG_MACH_JZ4780 and CONFIG_SMP directly
• Renamed JZ4780-specific SMP symbols to XBurst names
• Changed CPU enumeration to assign consecutive logical IDs and removed the explicit two-core limit
• Changed mailbox IRQ allocation failure from panic to logging and returning
• Shortened commit descriptions, removed Codex attribution, and adjusted source credits and sign-offs
• Kept the clock polling patch and CI20 defconfig changes unchanged,
  added Paul's R-b for patch #1
• Updated the kernel baseline to include additional upstream fixes

Florian Fainelli (2):
  clk: ingenic: Poll JZ4780 CPU1 power status atomically
  MIPS: Skip generic IPI setup for platform-specific callbacks

周琰杰 (Zhou Yanjie) (2):
  MIPS: Ingenic: Add XBurst SMP support
  MIPS: CI20: Enable SMP with two CPUs

 MAINTAINERS                           |   3 +-
 arch/mips/Kbuild                      |   1 +
 arch/mips/configs/ci20_defconfig      |   2 +
 arch/mips/generic/init.c              |   3 +
 arch/mips/include/asm/ingenic-smp.h   |  20 ++
 arch/mips/ingenic/Kconfig             |   2 +
 arch/mips/ingenic/Makefile            |   5 +
 arch/mips/ingenic/ingenic-smp-entry.S |  54 ++++++
 arch/mips/ingenic/ingenic-smp.c       | 260 ++++++++++++++++++++++++++
 arch/mips/kernel/idle.c               |  31 ++-
 arch/mips/kernel/smp.c                |   6 +-
 drivers/clk/ingenic/jz4780-cgu.c      |   4 +-
 12 files changed, 386 insertions(+), 5 deletions(-)
 create mode 100644 arch/mips/include/asm/ingenic-smp.h
 create mode 100644 arch/mips/ingenic/Makefile
 create mode 100644 arch/mips/ingenic/ingenic-smp-entry.S
 create mode 100644 arch/mips/ingenic/ingenic-smp.c


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v6 1/4] clk: ingenic: Poll JZ4780 CPU1 power status atomically
  2026-11-13 19:08 [PATCH v6 0/4] MIPS: CI20: Enable SMP with two CPUs Florian Fainelli
@ 2026-11-13 19:08 ` Florian Fainelli
  2026-11-13 19:08 ` [PATCH v6 2/4] MIPS: Skip generic IPI setup for platform-specific callbacks Florian Fainelli
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Florian Fainelli @ 2026-11-13 19:08 UTC (permalink / raw)
  To: linux-mips
  Cc: Florian Fainelli, stable, Paul Cercueil, Thomas Bogendoerfer,
	Paul Burton, Stephen Boyd, Brian Masney, Jerome Brunet,
	周琰杰 (Zhou Yanjie), Jiaxun Yang, open list,
	open list:COMMON CLK FRAMEWORK, hns, paul

The CPU1 clock enable callback runs under the clock framework's spinlock
with interrupts disabled. Its readl_poll_timeout() can sleep between
reads, which is invalid in this context when SMP powers up CPU1.

Use readl_poll_timeout_atomic() with the existing interval and timeout.
This is a prerequisite for the JZ4780 SMP bring-up path. The original
CPU1 clock implementation by Zhou Yanjie is already upstream.

Cross-built for CI20; the subsequent SMP-enabled image brought up both
CPU cores. Development and validation used Codex assistance.

CC: stable@vger.kernel.org
Fixes: 6673db4f3f26 ("clk: JZ4780: Add function for enable the second core.")
Link: https://lkml.kernel.org/r/1582215889-113034-3-git-send-email-zhouyanjie@wanyeetech.com
Reviewed-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Paul Cercueil <paul@crapouillou.net>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes since previous posting:
- No changes to this patch.

 drivers/clk/ingenic/jz4780-cgu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c
index 1e88aef7ac0f..1809f8859c7e 100644
--- a/drivers/clk/ingenic/jz4780-cgu.c
+++ b/drivers/clk/ingenic/jz4780-cgu.c
@@ -242,8 +242,8 @@ static int jz4780_core1_enable(struct clk_hw *hw)
 	spin_unlock_irqrestore(&cgu->lock, flags);
 
 	/* wait for the CPU to be powered up */
-	retval = readl_poll_timeout(cgu->base + CGU_REG_LCR, lcr,
-				 !(lcr & LCR_SCPUS), 10, timeout);
+	retval = readl_poll_timeout_atomic(cgu->base + CGU_REG_LCR, lcr,
+					   !(lcr & LCR_SCPUS), 10, timeout);
 	if (retval == -ETIMEDOUT) {
 		pr_err("%s: Wait for power up core1 timeout\n", __func__);
 		return retval;

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v6 2/4] MIPS: Skip generic IPI setup for platform-specific callbacks
  2026-11-13 19:08 [PATCH v6 0/4] MIPS: CI20: Enable SMP with two CPUs Florian Fainelli
  2026-11-13 19:08 ` [PATCH v6 1/4] clk: ingenic: Poll JZ4780 CPU1 power status atomically Florian Fainelli
@ 2026-11-13 19:08 ` Florian Fainelli
  2026-11-13 19:08 ` [PATCH v6 3/4] MIPS: Ingenic: Add XBurst SMP support Florian Fainelli
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Florian Fainelli @ 2026-11-13 19:08 UTC (permalink / raw)
  To: linux-mips
  Cc: Florian Fainelli, Thomas Bogendoerfer, Paul Burton, Paul Cercueil,
	Stephen Boyd, Brian Masney, Jerome Brunet,
	周琰杰 (Zhou Yanjie), Jiaxun Yang, open list,
	open list:COMMON CLK FRAMEWORK, hns, paul

A generic MIPS kernel can select a platform SMP backend with direct IPI
callbacks instead of an IPI IRQ domain. The XBurst backend uses CP0
mailboxes, so generic IPI allocation would find no domain and BUG when
more than one CPU is present.

Skip generic IPI initialization when neither selected send callback uses
the generic implementation. Keep initialization when either callback
uses generic IRQ IPIs, and retain the existing single-CPU shortcut.

Sashiko AI reported the XBurst integration issue; Codex assisted with
the change and extracted-function/build checks.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v6:

- addded missing Signed-off-by tag

Changes since previous posting:
- Split the generic IPI initialization guard out of the XBurst SMP patch
  as a prerequisite, as requested by Paul Cercueil.
- Add braces around the multi-line condition.

 arch/mips/kernel/smp.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 0f28b4a62e72..086298146dd8 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -338,8 +338,12 @@ int mips_smp_ipi_free(const struct cpumask *mask)
 
 static int __init mips_smp_ipi_init(void)
 {
-	if (num_possible_cpus() == 1)
+	/* Platforms with their own IPI callbacks do not need an IRQ domain. */
+	if ((mp_ops->send_ipi_single != mips_smp_send_ipi_single &&
+	     mp_ops->send_ipi_mask != mips_smp_send_ipi_mask) ||
+	    num_possible_cpus() == 1) {
 		return 0;
+	}
 
 	mips_smp_ipi_allocate(cpu_possible_mask);
 

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v6 3/4] MIPS: Ingenic: Add XBurst SMP support
  2026-11-13 19:08 [PATCH v6 0/4] MIPS: CI20: Enable SMP with two CPUs Florian Fainelli
  2026-11-13 19:08 ` [PATCH v6 1/4] clk: ingenic: Poll JZ4780 CPU1 power status atomically Florian Fainelli
  2026-11-13 19:08 ` [PATCH v6 2/4] MIPS: Skip generic IPI setup for platform-specific callbacks Florian Fainelli
@ 2026-11-13 19:08 ` Florian Fainelli
  2026-11-13 19:40   ` sashiko-bot
  2026-11-13 19:08 ` [PATCH v6 4/4] MIPS: CI20: Enable SMP with two CPUs Florian Fainelli
  2026-11-13 20:51 ` (subset) [PATCH v6 0/4] " Brian Masney
  4 siblings, 1 reply; 9+ messages in thread
From: Florian Fainelli @ 2026-11-13 19:08 UTC (permalink / raw)
  To: linux-mips
  Cc: 周琰杰 (Zhou Yanjie), Florian Fainelli,
	Thomas Bogendoerfer, Paul Burton, Paul Cercueil, Stephen Boyd,
	Brian Masney, Jerome Brunet, Jiaxun Yang, open list,
	open list:COMMON CLK FRAMEWORK, hns, paul

From: 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>

Add support for the second XBurst core on the JZ4780, based on Zhou
Yanjie's 2020 series and Paul Burton's original CI20 SMP implementation.
Use the CP0 mailboxes for inter-processor interrupts. Initialize CPU
presence and core IDs explicitly for generic kernels, and reject CPU
offlining until CPU teardown and restart are implemented.

XBurst stops its private cache clock when executing WAIT. Write back
the data cache before entering idle so that the other core can access
data belonging to the sleeping core. Select this wait handler only when
multiple CPUs are possible, and check pending work after the cache flush.

Enable the secondary clock outside the raw SMP lock. Use the CKSEG
aliases and pointer-sized assembly helpers for generic 64-bit builds.
Development and build/CI20 boot validation used Codex assistance; Sashiko
AI review identified the locking, topology and generic-kernel issues.

Link: https://lkml.iu.edu/hypermail/linux/kernel/2005.2/03488.html
Link: https://lists.openwall.net/linux-kernel/2020/05/13/1482
Link: https://lists.openwall.net/linux-kernel/2020/05/19/1099
Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
[florian: forward ported to latest version]
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
No changes in v6

Changes since previous posting:
- Move the generic IPI initialization guard into a separate prerequisite.
- Remove Paul Cercueil's Reviewed-by and Tested-by tags after the changes.
- Remove the CONFIG_HOTPLUG_CPU guard around xburst_cpu_disable() and mark
  it __maybe_unused. Retain the initializer guard because plat_smp_ops has
  no cpu_disable member when hotplug is disabled; PTR_IF() cannot fix that.
- Document the intentional work recheck after the data-cache flush: the
  first need_resched() avoids an unnecessary flush, and the second checks
  for work arriving during it.

Earlier changes since v3:
- Enable CPU1's clock outside the raw SMP lock.
- Initialize CPU presence and core IDs; reject unsupported CPU offlining.
- Use CKSEG aliases and pointer/long assembly helpers for 64-bit builds.
- Restrict the XBurst idle handler to systems with multiple possible CPUs
  and check pending work after the cache flush.

Validation:
- Affected objects build for CI20 without CPU hotplug and generic Ingenic
  32-bit and 64-bit configurations with CPU hotplug.
- The previous tree booted on CI20 with both CPUs online and successful
  workers pinned to each CPU. All 11 functional boot-smoke checks passed;
  the kernel-log check failed on DRM bridge/refcount warnings.
- This revision changes no runtime behavior and has not been rebooted.

Development and validation used Codex assistance. Sashiko AI review
identified the issues addressed by the changes since v3.

 MAINTAINERS                           |   3 +-
 arch/mips/Kbuild                      |   1 +
 arch/mips/generic/init.c              |   3 +
 arch/mips/include/asm/ingenic-smp.h   |  20 ++
 arch/mips/ingenic/Kconfig             |   2 +
 arch/mips/ingenic/Makefile            |   5 +
 arch/mips/ingenic/ingenic-smp-entry.S |  54 ++++++
 arch/mips/ingenic/ingenic-smp.c       | 260 ++++++++++++++++++++++++++
 arch/mips/kernel/idle.c               |  31 ++-
 9 files changed, 377 insertions(+), 2 deletions(-)
 create mode 100644 arch/mips/include/asm/ingenic-smp.h
 create mode 100644 arch/mips/ingenic/Makefile
 create mode 100644 arch/mips/ingenic/ingenic-smp-entry.S
 create mode 100644 arch/mips/ingenic/ingenic-smp.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 222b7fc2c3aa..7128df320bab 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13150,8 +13150,9 @@ L:	linux-mips@vger.kernel.org
 S:	Maintained
 F:	arch/mips/boot/dts/ingenic/
 F:	arch/mips/generic/board-ingenic.c
+F:	arch/mips/include/asm/ingenic-smp.h
 F:	arch/mips/include/asm/mach-ingenic/
-F:	arch/mips/ingenic/Kconfig
+F:	arch/mips/ingenic/
 F:	drivers/clk/ingenic/
 F:	drivers/dma/dma-jz4780.c
 F:	drivers/gpu/drm/ingenic/
diff --git a/arch/mips/Kbuild b/arch/mips/Kbuild
index e901bf554483..4912ab80d143 100644
--- a/arch/mips/Kbuild
+++ b/arch/mips/Kbuild
@@ -12,6 +12,7 @@ obj- := $(platform-y)
 # The object files are linked as core-y files would be linked
 
 obj-y += generic/
+obj-$(CONFIG_MACH_INGENIC) += ingenic/
 obj-y += kernel/
 obj-y += mm/
 obj-y += net/
diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c
index 1d712eac1617..38f294887c17 100644
--- a/arch/mips/generic/init.c
+++ b/arch/mips/generic/init.c
@@ -13,6 +13,7 @@
 
 #include <asm/bootinfo.h>
 #include <asm/fw/fw.h>
+#include <asm/ingenic-smp.h>
 #include <asm/irq_cpu.h>
 #include <asm/machine.h>
 #include <asm/mips-cps.h>
@@ -113,6 +114,8 @@ void __init device_tree_init(void)
 	unflatten_and_copy_device_tree();
 	mips_cpc_probe();
 
+	if (!register_ingenic_smp_ops())
+		return;
 	if (!register_cps_smp_ops())
 		return;
 	if (!register_vsmp_smp_ops())
diff --git a/arch/mips/include/asm/ingenic-smp.h b/arch/mips/include/asm/ingenic-smp.h
new file mode 100644
index 000000000000..ea81c333820d
--- /dev/null
+++ b/arch/mips/include/asm/ingenic-smp.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2013 Paul Burton <paulburton@kernel.org> */
+#ifndef __ASM_INGENIC_SMP_H__
+#define __ASM_INGENIC_SMP_H__
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kconfig.h>
+
+#if defined(CONFIG_MACH_JZ4780) && defined(CONFIG_SMP)
+int __init register_ingenic_smp_ops(void);
+void xburst_secondary_cpu_entry(void);
+#else
+static inline int register_ingenic_smp_ops(void)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* __ASM_INGENIC_SMP_H__ */
diff --git a/arch/mips/ingenic/Kconfig b/arch/mips/ingenic/Kconfig
index f595b339a4b8..583f8d3651df 100644
--- a/arch/mips/ingenic/Kconfig
+++ b/arch/mips/ingenic/Kconfig
@@ -64,6 +64,8 @@ config MACH_JZ4780
 	select MIPS_CPU_SCACHE
 	select SYS_HAS_CPU_MIPS32_R2
 	select SYS_SUPPORTS_HIGHMEM
+	select SYS_SUPPORTS_SMP
+	select SMP_UP if SMP
 
 config MACH_X1000
 	bool
diff --git a/arch/mips/ingenic/Makefile b/arch/mips/ingenic/Makefile
new file mode 100644
index 000000000000..fc3b1bf1f25a
--- /dev/null
+++ b/arch/mips/ingenic/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+ifdef CONFIG_SMP
+obj-$(CONFIG_MACH_JZ4780) += ingenic-smp.o ingenic-smp-entry.o
+endif
diff --git a/arch/mips/ingenic/ingenic-smp-entry.S b/arch/mips/ingenic/ingenic-smp-entry.S
new file mode 100644
index 000000000000..290e23c65707
--- /dev/null
+++ b/arch/mips/ingenic/ingenic-smp-entry.S
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2013 Paul Burton <paulburton@kernel.org>
+ * XBurst secondary CPU reset entry
+ */
+
+#include <asm/addrspace.h>
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/cacheops.h>
+#include <asm/mipsregs.h>
+
+#define CACHE_SIZE	(32 * 1024)
+#define CACHE_LINESIZE	32
+
+	/* The CP0 REIM register only stores the upper 16 address bits. */
+	.section .text.smp-entry, "ax"
+	.balign 0x10000
+	.set noreorder
+LEAF(xburst_secondary_cpu_entry)
+	mtc0	zero, CP0_CAUSE
+	li	t0, ST0_CU0
+	mtc0	t0, CP0_STATUS
+	ehb
+
+	/* Invalidate both private caches before entering cached code. */
+	PTR_LI	t0, CKSEG0
+	ori	t1, t0, CACHE_SIZE
+	mtc0	zero, CP0_TAGLO
+	ehb
+1:	cache	Index_Store_Tag_I, 0(t0)
+	cache	Index_Store_Tag_D, 0(t0)
+	addiu	t0, t0, CACHE_LINESIZE
+	bne	t0, t1, 1b
+	 nop
+
+	mfc0	t0, CP0_CONFIG
+	li	t1, ~CONF_CM_CMASK
+	and	t0, t0, t1
+	ori	t0, t0, CONF_CM_CACHABLE_NONCOHERENT
+	mtc0	t0, CP0_CONFIG
+	mtc0	zero, CP0_PAGEMASK
+	ehb
+
+	/* CPU0 publishes these in RAM before releasing CPU1 from reset. */
+	PTR_LA	t0, xburst_cpu_entry_sp
+	LONG_L	sp, 0(t0)
+	PTR_LA	t0, xburst_cpu_entry_gp
+	LONG_L	gp, 0(t0)
+
+	PTR_LA	t0, smp_bootstrap
+	jr	t0
+	 nop
+END(xburst_secondary_cpu_entry)
diff --git a/arch/mips/ingenic/ingenic-smp.c b/arch/mips/ingenic/ingenic-smp.c
new file mode 100644
index 000000000000..27b9b573a7e0
--- /dev/null
+++ b/arch/mips/ingenic/ingenic-smp.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * XBurst SMP support, based on Paul Burton's CI20 implementation and
+ * Zhou Yanjie's 2020 JZ4780 SMP series.
+ * Copyright (C) 2013 Paul Burton <paulburton@kernel.org>
+ */
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_clk.h>
+#include <linux/sched/task_stack.h>
+#include <linux/smp.h>
+
+#include <asm/addrspace.h>
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/r4kcache.h>
+#include <asm/smp-ops.h>
+
+#include <asm/ingenic-smp.h>
+
+#define read_c0_corectrl()	__read_32bit_c0_register($12, 2)
+#define write_c0_corectrl(val)	__write_32bit_c0_register($12, 2, val)
+#define read_c0_corestatus()	__read_32bit_c0_register($12, 3)
+#define write_c0_corestatus(val)	__write_32bit_c0_register($12, 3, val)
+#define read_c0_reim()		__read_32bit_c0_register($12, 4)
+#define write_c0_reim(val)	__write_32bit_c0_register($12, 4, val)
+#define read_c0_mailbox0()	__read_32bit_c0_register($20, 0)
+#define write_c0_mailbox0(val)	__write_32bit_c0_register($20, 0, val)
+#define read_c0_mailbox1()	__read_32bit_c0_register($20, 1)
+#define write_c0_mailbox1(val)	__write_32bit_c0_register($20, 1, val)
+
+#define XBURST_MBOX_IRQ		(MIPS_CPU_IRQ_BASE + 3)
+#define CORECTRL_SWRST(cpu)	BIT(cpu)
+#define CORECTRL_RPC(cpu)	BIT(8 + (cpu))
+#define CORESTATUS_MIRQ(cpu)	BIT(cpu)
+#define REIM_ENTRY		GENMASK(31, 16)
+#define REIM_MBOXIRQ(cpu)	BIT(cpu)
+
+static struct clk *cpu1_clock;
+static DEFINE_RAW_SPINLOCK(smp_lock);
+
+/* Referenced by the uncached secondary CPU reset entry. */
+unsigned long xburst_cpu_entry_sp;
+unsigned long xburst_cpu_entry_gp;
+
+static irqreturn_t xburst_mbox_interrupt(int irq, void *dev_id)
+{
+	unsigned int cpu = cpu_logical_map(smp_processor_id());
+	u32 action, status;
+
+	raw_spin_lock(&smp_lock);
+	if (cpu == 0) {
+		action = read_c0_mailbox0();
+		write_c0_mailbox0(0);
+	} else {
+		action = read_c0_mailbox1();
+		write_c0_mailbox1(0);
+	}
+
+	status = read_c0_corestatus();
+	write_c0_corestatus(status & ~CORESTATUS_MIRQ(cpu));
+	irq_disable_hazard();
+	raw_spin_unlock(&smp_lock);
+
+	if (action & SMP_RESCHEDULE_YOURSELF)
+		scheduler_ipi();
+	if (action & SMP_CALL_FUNCTION)
+		generic_smp_call_function_interrupt();
+
+	return IRQ_HANDLED;
+}
+
+static void __init xburst_smp_setup(void)
+{
+	struct device_node *np;
+	u32 entry, reim;
+	unsigned int cpu = 0;
+	u64 hwid;
+
+	for_each_of_cpu_node(np) {
+		hwid = of_get_cpu_hwid(np, 0);
+		if (!of_device_is_available(np) ||
+		    hwid >= ARRAY_SIZE(__cpu_number_map))
+			continue;
+		if (cpu >= nr_cpu_ids) {
+			of_node_put(np);
+			break;
+		}
+		__cpu_number_map[hwid] = cpu;
+		__cpu_logical_map[cpu] = hwid;
+		set_cpu_possible(cpu, true);
+		set_cpu_present(cpu, true);
+		cpu_set_core(&cpu_data[cpu], hwid);
+		cpu++;
+	}
+
+	/* Program the shared reset vector with mailbox delivery masked. */
+	reim = read_c0_reim();
+	reim &= ~(REIM_MBOXIRQ(0) | REIM_MBOXIRQ(1));
+	write_c0_reim(reim);
+	write_c0_mailbox0(0);
+	write_c0_mailbox1(0);
+	write_c0_corestatus(0);
+
+	entry = CKSEG1ADDR((unsigned long)xburst_secondary_cpu_entry);
+	write_c0_reim((reim & ~REIM_ENTRY) | (entry & REIM_ENTRY));
+}
+
+static void __init xburst_prepare_cpus(unsigned int max_cpus)
+{
+	struct device_node *np;
+	u32 reim;
+	int ret;
+
+	ret = request_irq(XBURST_MBOX_IRQ, xburst_mbox_interrupt,
+			  IRQF_PERCPU | IRQF_NO_THREAD, "core mailbox", NULL);
+	if (ret) {
+		pr_err("XBurst: cannot request mailbox IRQ: %d\n", ret);
+		return;
+	}
+
+	reim = read_c0_reim();
+	write_c0_reim(reim | REIM_MBOXIRQ(0));
+	set_c0_status(STATUSF_IP3);
+	irq_enable_hazard();
+
+	if (!cpu_possible(1))
+		return;
+
+	np = of_get_cpu_node(1, NULL);
+	cpu1_clock = of_clk_get(np, 0);
+	of_node_put(np);
+	if (IS_ERR(cpu1_clock)) {
+		pr_err("XBurst: cannot get CPU1 clock: %ld\n",
+		       PTR_ERR(cpu1_clock));
+		return;
+	}
+
+	ret = clk_prepare(cpu1_clock);
+	if (ret) {
+		clk_put(cpu1_clock);
+		cpu1_clock = ERR_PTR(ret);
+		pr_err("XBurst: cannot prepare CPU1 clock: %d\n", ret);
+	}
+}
+
+static int xburst_boot_secondary(int cpu, struct task_struct *idle)
+{
+	unsigned long flags;
+	u32 ctrl;
+	int ret;
+
+	if (cpu_logical_map(cpu) != 1 || IS_ERR_OR_NULL(cpu1_clock))
+		return -ENODEV;
+
+	raw_spin_lock_irqsave(&smp_lock, flags);
+	ctrl = read_c0_corectrl() | CORECTRL_SWRST(1) | CORECTRL_RPC(1);
+	write_c0_corectrl(ctrl);
+	back_to_back_c0_hazard();
+	raw_spin_unlock_irqrestore(&smp_lock, flags);
+
+	ret = clk_enable(cpu1_clock);
+	if (ret)
+		return ret;
+
+	xburst_cpu_entry_sp = __KSTK_TOS(idle);
+	xburst_cpu_entry_gp = (unsigned long)task_thread_info(idle);
+	/* Publish bootstrap state before CPU1 starts using its private cache. */
+	r4k_blast_dcache();
+	/* Complete cache writeback before releasing reset. */
+	mb();
+	raw_spin_lock_irqsave(&smp_lock, flags);
+	ctrl = read_c0_corectrl();
+	write_c0_corectrl(ctrl & ~CORECTRL_SWRST(1));
+	back_to_back_c0_hazard();
+	raw_spin_unlock_irqrestore(&smp_lock, flags);
+	return 0;
+}
+
+static void xburst_init_secondary(void)
+{
+	clear_c0_status(ST0_IM);
+	irq_disable_hazard();
+}
+
+static void xburst_smp_finish(void)
+{
+	unsigned int cpu = cpu_logical_map(smp_processor_id());
+	u32 reim;
+
+	raw_spin_lock(&smp_lock);
+	reim = read_c0_reim();
+	write_c0_reim(reim | REIM_MBOXIRQ(cpu));
+	raw_spin_unlock(&smp_lock);
+
+	change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP2 |
+			 STATUSF_IP1 | STATUSF_IP0);
+	irq_enable_hazard();
+	local_irq_enable();
+}
+
+static void xburst_send_ipi_locked(int cpu, unsigned int action)
+{
+	if (cpu_logical_map(cpu) == 0)
+		write_c0_mailbox0(read_c0_mailbox0() | action);
+	else
+		write_c0_mailbox1(read_c0_mailbox1() | action);
+	back_to_back_c0_hazard();
+}
+
+static void xburst_send_ipi_single(int cpu, unsigned int action)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&smp_lock, flags);
+	xburst_send_ipi_locked(cpu, action);
+	raw_spin_unlock_irqrestore(&smp_lock, flags);
+}
+
+static void xburst_send_ipi_mask(const struct cpumask *mask, unsigned int action)
+{
+	unsigned long flags;
+	int cpu;
+
+	raw_spin_lock_irqsave(&smp_lock, flags);
+	for_each_cpu(cpu, mask)
+		xburst_send_ipi_locked(cpu, action);
+	raw_spin_unlock_irqrestore(&smp_lock, flags);
+}
+
+static int __maybe_unused xburst_cpu_disable(void)
+{
+	/* CPU teardown and restart are not supported yet. */
+	return -EOPNOTSUPP;
+}
+
+static const struct plat_smp_ops xburst_smp_ops = {
+	.send_ipi_single = xburst_send_ipi_single,
+	.send_ipi_mask = xburst_send_ipi_mask,
+	.init_secondary = xburst_init_secondary,
+	.smp_finish = xburst_smp_finish,
+	.boot_secondary = xburst_boot_secondary,
+	.smp_setup = xburst_smp_setup,
+	.prepare_cpus = xburst_prepare_cpus,
+#ifdef CONFIG_HOTPLUG_CPU
+	.cpu_disable = xburst_cpu_disable,
+#endif
+};
+
+int __init register_ingenic_smp_ops(void)
+{
+	if (!of_machine_is_compatible("ingenic,jz4780"))
+		return -ENODEV;
+
+	register_smp_ops(&xburst_smp_ops);
+	return 0;
+}
diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c
index 80e8a04a642e..6c44715d81d5 100644
--- a/arch/mips/kernel/idle.c
+++ b/arch/mips/kernel/idle.c
@@ -18,6 +18,7 @@
 #include <asm/cpu-type.h>
 #include <asm/idle.h>
 #include <asm/mipsregs.h>
+#include <asm/r4kcache.h>
 
 /*
  * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
@@ -71,6 +72,28 @@ static void __cpuidle rm7k_wait_irqoff(void)
 		"	.set	pop					\n");
 }
 
+/* XBurst gates its private cache clock in WAIT; write back dirty data first. */
+static void __cpuidle xburst_wait_irqoff(void)
+{
+	unsigned long pending;
+
+	if (need_resched())
+		return;
+
+	r4k_blast_dcache();
+	/* Recheck work that may have arrived during the cache flush. */
+	pending = read_c0_cause() & read_c0_status() & CAUSEF_IP;
+	if (!need_resched() && !pending) {
+		__asm__ __volatile__(
+			".set push\n"
+			".set arch=r4000\n"
+			"sync\n"
+			"wait\n"
+			".set pop\n"
+			: : : "memory");
+	}
+}
+
 /*
  * Au1 'wait' is only useful when the 32kHz counter is used as timer,
  * since coreclock (and the cp0 counter) stops upon executing it. Only an
@@ -156,10 +179,16 @@ void __init check_wait(void)
 	case CPU_CAVIUM_OCTEON_PLUS:
 	case CPU_CAVIUM_OCTEON2:
 	case CPU_CAVIUM_OCTEON3:
-	case CPU_XBURST:
 	case CPU_LOONGSON32:
 		cpu_wait = r4k_wait;
 		break;
+	case CPU_XBURST:
+		if (IS_ENABLED(CONFIG_MACH_JZ4780) &&
+		    IS_ENABLED(CONFIG_SMP) && num_possible_cpus() > 1)
+			cpu_wait = xburst_wait_irqoff;
+		else
+			cpu_wait = r4k_wait;
+		break;
 	case CPU_LOONGSON64:
 		if ((c->processor_id & (PRID_IMP_MASK | PRID_REV_MASK)) >=
 				(PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_0) ||

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v6 4/4] MIPS: CI20: Enable SMP with two CPUs
  2026-11-13 19:08 [PATCH v6 0/4] MIPS: CI20: Enable SMP with two CPUs Florian Fainelli
                   ` (2 preceding siblings ...)
  2026-11-13 19:08 ` [PATCH v6 3/4] MIPS: Ingenic: Add XBurst SMP support Florian Fainelli
@ 2026-11-13 19:08 ` Florian Fainelli
  2026-11-13 20:51 ` (subset) [PATCH v6 0/4] " Brian Masney
  4 siblings, 0 replies; 9+ messages in thread
From: Florian Fainelli @ 2026-11-13 19:08 UTC (permalink / raw)
  To: linux-mips
  Cc: 周琰杰 (Zhou Yanjie), Paul Cercueil,
	Florian Fainelli, Thomas Bogendoerfer, Paul Burton, Stephen Boyd,
	Brian Masney, Jerome Brunet, Jiaxun Yang, open list,
	open list:COMMON CLK FRAMEWORK, hns, paul

From: 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>

Enable both JZ4780 cores now that the generic Ingenic platform provides
secondary CPU reset and mailbox support. The existing device tree
already reserves TCU channels for both per-CPU clock events.

Link: https://lists.openwall.net/linux-kernel/2020/05/19/739
Reviewed-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Paul Cercueil <paul@crapouillou.net>
Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
No changes in v6

Changes since previous posting:
- No changes to this patch; renumbered after the IPI prerequisite split.

 arch/mips/configs/ci20_defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/mips/configs/ci20_defconfig b/arch/mips/configs/ci20_defconfig
index 90536cab417e..09d65094b1bd 100644
--- a/arch/mips/configs/ci20_defconfig
+++ b/arch/mips/configs/ci20_defconfig
@@ -22,6 +22,8 @@ CONFIG_EXPERT=y
 CONFIG_MACH_INGENIC_SOC=y
 CONFIG_JZ4780_CI20=y
 CONFIG_HIGHMEM=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
 CONFIG_HZ_100=y
 # CONFIG_SUSPEND is not set
 # CONFIG_SECCOMP is not set

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v6 3/4] MIPS: Ingenic: Add XBurst SMP support
  2026-11-13 19:08 ` [PATCH v6 3/4] MIPS: Ingenic: Add XBurst SMP support Florian Fainelli
@ 2026-11-13 19:40   ` sashiko-bot
  2026-11-13 21:52     ` Florian Fainelli
  0 siblings, 1 reply; 9+ messages in thread
From: sashiko-bot @ 2026-11-13 19:40 UTC (permalink / raw)
  To: Florian Fainelli; +Cc: open list:COMMON CLK FRAMEWORK

Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [High] mips: idle: cached need_resched() load after dcache flush in
  xburst_wait_irqoff()
- [Medium] MIPS: Ingenic: missing IRQF_NO_SUSPEND on mailbox IPI in
  xburst_prepare_cpus()
- [Low] mips: idle: xburst_wait_irqoff() calls non-noinstr
  r4k_blast_dcache()
--

commit 2871a54058216bdde1330a67071ead0fedc13363
Author: 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>

MIPS: Ingenic: Add XBurst SMP support

This commit adds SMP support for the second XBurst core on the JZ4780 SoC
using CP0 mailboxes for IPIs and adds an XBurst idle handler that flushes
the private data cache before executing the wait instruction.

Link: https://lkml.iu.edu/hypermail/linux/kernel/2005.2/03488.html
Link: https://lists.openwall.net/linux-kernel/2020/05/13/1482
Link: https://lists.openwall.net/linux-kernel/2020/05/19/1099

> diff --git a/arch/mips/ingenic/ingenic-smp.c b/arch/mips/ingenic/ingenic-smp.c
> new file mode 100644
> index 0000000000000..27b9b573a7e07
> --- /dev/null
> +++ b/arch/mips/ingenic/ingenic-smp.c

[ ... ]

> +static void __init xburst_prepare_cpus(unsigned int max_cpus)
> +{
> +	struct device_node *np;
> +	u32 reim;
> +	int ret;
> +
> +	ret = request_irq(XBURST_MBOX_IRQ, xburst_mbox_interrupt,
> +			  IRQF_PERCPU | IRQF_NO_THREAD, "core mailbox", NULL);

[Severity: Medium]
Should this request_irq() call include IRQF_NO_SUSPEND?

Unlike request_percpu_irq(), request_irq() with IRQF_PERCPU does not set
IRQF_NO_SUSPEND automatically, leaving desc->no_suspend_depth at 0.  During
system suspend (such as suspend-to-idle), suspend_device_irqs() disables
XBURST_MBOX_IRQ, which runs mask_mips_irq() and clears STATUSF_IP3 in
CP0_STATUS on the calling CPU.  That blocks IPIs during noirq suspend and
s2idle, and if resume_device_irqs() runs on the other CPU, STATUSF_IP3 stays
masked after resume and hangs subsequent cross-CPU smp_call_function() calls.

> diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c
> index 80e8a04a642e0..6c44715d81d5b 100644
> --- a/arch/mips/kernel/idle.c
> +++ b/arch/mips/kernel/idle.c
> @@ -18,6 +18,7 @@
>  #include <asm/cpu-type.h>
>  #include <asm/idle.h>
>  #include <asm/mipsregs.h>
> +#include <asm/r4kcache.h>
>  
>  /*
>   * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
> @@ -71,6 +72,28 @@ static void __cpuidle rm7k_wait_irqoff(void)
>  		"	.set	pop					\n");
>  }
>  
> +/* XBurst gates its private cache clock in WAIT; write back dirty data first. */
> +static void __cpuidle xburst_wait_irqoff(void)
> +{
> +	unsigned long pending;
> +
> +	if (need_resched())
> +		return;
> +
> +	r4k_blast_dcache();

[Severity: Low]
Does calling r4k_blast_dcache() from __cpuidle xburst_wait_irqoff() violate
noinstr idle rules?

xburst_wait_irqoff() runs between ct_cpuidle_enter() and ct_cpuidle_exit()
while RCU is not watching, but r4k_blast_dcache() calls out-of-line
blast_dcache32() in .text, which only has notrace from inline and lacks
__no_sanitize_coverage, __no_profile and __no_kcsan.  Besides making
cpu_in_idle() return false during the flush, builds with CONFIG_KCOV,
CONFIG_GCOV_PROFILE_ALL or CONFIG_KCSAN run instrumentation while RCU is not
watching and dirty the private L1 D-cache on return from blast_dcache32()
right before wait gates the cache clock.

> +	/* Recheck work that may have arrived during the cache flush. */
> +	pending = read_c0_cause() & read_c0_status() & CAUSEF_IP;
> +	if (!need_resched() && !pending) {

[Severity: High]
Does calling need_resched() after r4k_blast_dcache() pull the idle task's
struct thread_info cache line back into the private L1 D-cache right before
wait stops the cache clock?

need_resched() loads current_thread_info()->flags from KSEG0 cacheable
memory, caching the line with _TIF_NEED_RESCHED clear in the sleeping CPU's
private L1 D-cache.  When the other CPU sets _TIF_NEED_RESCHED on the idle
thread_info->flags and sends SMP_RESCHEDULE_YOURSELF while the cache clock is
gated:

CPU0                              CPU1
xburst_wait_irqoff()
  r4k_blast_dcache()
  need_resched()
    /* caches thread_info with
     * _TIF_NEED_RESCHED == 0
     */
  wait
                                  resched_curr()
                                    set_tsk_need_resched(idle)
                                    smp_send_reschedule()
  <mailbox IPI wakes CPU>
  handle_int / irq_enter()
    /* writes regs / preempt_count
     * in stale thread_info line
     */
  scheduler_ipi() /* no-op */
  /* _TIF_NEED_RESCHED lost */

On MIPS, scheduler_ipi() does not modify thread_info->flags, so when CPU0
takes the interrupt and writes other fields in the same 32-byte struct
thread_info cache line (or if remote snoops stall while the cache clock is
stopped), the reschedule is lost or the waking CPU stalls.  Since local IRQs
are disabled and any remote wakeup during r4k_blast_dcache() raises the
mailbox IPI in CP0_CAUSE, checking pending alone avoids touching the D-cache
after the flush.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261113190836.470937-1-f.fainelli@gmail.com?part=3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: (subset) [PATCH v6 0/4] MIPS: CI20: Enable SMP with two CPUs
  2026-11-13 19:08 [PATCH v6 0/4] MIPS: CI20: Enable SMP with two CPUs Florian Fainelli
                   ` (3 preceding siblings ...)
  2026-11-13 19:08 ` [PATCH v6 4/4] MIPS: CI20: Enable SMP with two CPUs Florian Fainelli
@ 2026-11-13 20:51 ` Brian Masney
  2026-11-13 21:52   ` Florian Fainelli
  4 siblings, 1 reply; 9+ messages in thread
From: Brian Masney @ 2026-11-13 20:51 UTC (permalink / raw)
  To: linux-mips, Florian Fainelli
  Cc: Thomas Bogendoerfer, Paul Burton, Paul Cercueil, Stephen Boyd,
	Brian Masney, Jerome Brunet,
	周琰杰 (Zhou Yanjie), Jiaxun Yang, linux-kernel,
	linux-clk, hns, paul, Brian Masney


On Fri, 13 Nov 2026 11:08:32 -0800, Florian Fainelli wrote:
> MIPS: CI20: Enable SMP with two CPUs
> 
> This patch series resurrects SMP support for the CI20 board. This was
> submitted back in 2020 by Zhou Yanjie.
> 
> Changes in v6:
> 
> [...]

Applied, thanks!

[1/4] clk: ingenic: Poll JZ4780 CPU1 power status atomically
      https://git.kernel.org/clk/linux/c/2c45b7e1e2f7

Best regards,
-- 
Brian Masney <masneyb@kernel.org>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: (subset) [PATCH v6 0/4] MIPS: CI20: Enable SMP with two CPUs
  2026-11-13 20:51 ` (subset) [PATCH v6 0/4] " Brian Masney
@ 2026-11-13 21:52   ` Florian Fainelli
  0 siblings, 0 replies; 9+ messages in thread
From: Florian Fainelli @ 2026-11-13 21:52 UTC (permalink / raw)
  To: Brian Masney, linux-mips
  Cc: Thomas Bogendoerfer, Paul Burton, Paul Cercueil, Stephen Boyd,
	Brian Masney, Jerome Brunet,
	周琰杰 (Zhou Yanjie), Jiaxun Yang, linux-kernel,
	linux-clk, hns, paul

On 11/13/26 12:51, Brian Masney wrote:
> 
> On Fri, 13 Nov 2026 11:08:32 -0800, Florian Fainelli wrote:
>> MIPS: CI20: Enable SMP with two CPUs
>>
>> This patch series resurrects SMP support for the CI20 board. This was
>> submitted back in 2020 by Zhou Yanjie.
>>
>> Changes in v6:
>>
>> [...]
> 
> Applied, thanks!
> 
> [1/4] clk: ingenic: Poll JZ4780 CPU1 power status atomically
>        https://git.kernel.org/clk/linux/c/2c45b7e1e2f7
> 
> Best regards,

Thanks Brian, I will remove that patch from future submissions.
-- 
Florian

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v6 3/4] MIPS: Ingenic: Add XBurst SMP support
  2026-11-13 19:40   ` sashiko-bot
@ 2026-11-13 21:52     ` Florian Fainelli
  0 siblings, 0 replies; 9+ messages in thread
From: Florian Fainelli @ 2026-11-13 21:52 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: open list:COMMON CLK FRAMEWORK

On 11/13/26 11:40, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential
> issues to consider:
> - [High] mips: idle: cached need_resched() load after dcache flush in
>    xburst_wait_irqoff()
> - [Medium] MIPS: Ingenic: missing IRQF_NO_SUSPEND on mailbox IPI in
>    xburst_prepare_cpus()
> - [Low] mips: idle: xburst_wait_irqoff() calls non-noinstr
>    r4k_blast_dcache()
> --
> 
> commit 2871a54058216bdde1330a67071ead0fedc13363
> Author: 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
> 
> MIPS: Ingenic: Add XBurst SMP support
> 
> This commit adds SMP support for the second XBurst core on the JZ4780 SoC
> using CP0 mailboxes for IPIs and adds an XBurst idle handler that flushes
> the private data cache before executing the wait instruction.
> 
> Link: https://lkml.iu.edu/hypermail/linux/kernel/2005.2/03488.html
> Link: https://lists.openwall.net/linux-kernel/2020/05/13/1482
> Link: https://lists.openwall.net/linux-kernel/2020/05/19/1099
> 
>> diff --git a/arch/mips/ingenic/ingenic-smp.c b/arch/mips/ingenic/ingenic-smp.c
>> new file mode 100644
>> index 0000000000000..27b9b573a7e07
>> --- /dev/null
>> +++ b/arch/mips/ingenic/ingenic-smp.c
> 
> [ ... ]
> 
>> +static void __init xburst_prepare_cpus(unsigned int max_cpus)
>> +{
>> +	struct device_node *np;
>> +	u32 reim;
>> +	int ret;
>> +
>> +	ret = request_irq(XBURST_MBOX_IRQ, xburst_mbox_interrupt,
>> +			  IRQF_PERCPU | IRQF_NO_THREAD, "core mailbox", NULL);
> 
> [Severity: Medium]
> Should this request_irq() call include IRQF_NO_SUSPEND?
> 
> Unlike request_percpu_irq(), request_irq() with IRQF_PERCPU does not set
> IRQF_NO_SUSPEND automatically, leaving desc->no_suspend_depth at 0.  During
> system suspend (such as suspend-to-idle), suspend_device_irqs() disables
> XBURST_MBOX_IRQ, which runs mask_mips_irq() and clears STATUSF_IP3 in
> CP0_STATUS on the calling CPU.  That blocks IPIs during noirq suspend and
> s2idle, and if resume_device_irqs() runs on the other CPU, STATUSF_IP3 stays
> masked after resume and hangs subsequent cross-CPU smp_call_function() calls.
> 
>> diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c
>> index 80e8a04a642e0..6c44715d81d5b 100644
>> --- a/arch/mips/kernel/idle.c
>> +++ b/arch/mips/kernel/idle.c
>> @@ -18,6 +18,7 @@
>>   #include <asm/cpu-type.h>
>>   #include <asm/idle.h>
>>   #include <asm/mipsregs.h>
>> +#include <asm/r4kcache.h>
>>   
>>   /*
>>    * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
>> @@ -71,6 +72,28 @@ static void __cpuidle rm7k_wait_irqoff(void)
>>   		"	.set	pop					\n");
>>   }
>>   
>> +/* XBurst gates its private cache clock in WAIT; write back dirty data first. */
>> +static void __cpuidle xburst_wait_irqoff(void)
>> +{
>> +	unsigned long pending;
>> +
>> +	if (need_resched())
>> +		return;
>> +
>> +	r4k_blast_dcache();
> 
> [Severity: Low]
> Does calling r4k_blast_dcache() from __cpuidle xburst_wait_irqoff() violate
> noinstr idle rules?
> 
> xburst_wait_irqoff() runs between ct_cpuidle_enter() and ct_cpuidle_exit()
> while RCU is not watching, but r4k_blast_dcache() calls out-of-line
> blast_dcache32() in .text, which only has notrace from inline and lacks
> __no_sanitize_coverage, __no_profile and __no_kcsan.  Besides making
> cpu_in_idle() return false during the flush, builds with CONFIG_KCOV,
> CONFIG_GCOV_PROFILE_ALL or CONFIG_KCSAN run instrumentation while RCU is not
> watching and dirty the private L1 D-cache on return from blast_dcache32()
> right before wait gates the cache clock.
> 
>> +	/* Recheck work that may have arrived during the cache flush. */
>> +	pending = read_c0_cause() & read_c0_status() & CAUSEF_IP;
>> +	if (!need_resched() && !pending) {
> 
> [Severity: High]
> Does calling need_resched() after r4k_blast_dcache() pull the idle task's
> struct thread_info cache line back into the private L1 D-cache right before
> wait stops the cache clock?
> 
> need_resched() loads current_thread_info()->flags from KSEG0 cacheable
> memory, caching the line with _TIF_NEED_RESCHED clear in the sleeping CPU's
> private L1 D-cache.  When the other CPU sets _TIF_NEED_RESCHED on the idle
> thread_info->flags and sends SMP_RESCHEDULE_YOURSELF while the cache clock is
> gated:
> 
> CPU0                              CPU1
> xburst_wait_irqoff()
>    r4k_blast_dcache()
>    need_resched()
>      /* caches thread_info with
>       * _TIF_NEED_RESCHED == 0
>       */
>    wait
>                                    resched_curr()
>                                      set_tsk_need_resched(idle)
>                                      smp_send_reschedule()
>    <mailbox IPI wakes CPU>
>    handle_int / irq_enter()
>      /* writes regs / preempt_count
>       * in stale thread_info line
>       */
>    scheduler_ipi() /* no-op */
>    /* _TIF_NEED_RESCHED lost */
> 
> On MIPS, scheduler_ipi() does not modify thread_info->flags, so when CPU0
> takes the interrupt and writes other fields in the same 32-byte struct
> thread_info cache line (or if remote snoops stall while the cache clock is
> stopped), the reschedule is lost or the waking CPU stalls.  Since local IRQs
> are disabled and any remote wakeup during r4k_blast_dcache() raises the
> mailbox IPI in CP0_CAUSE, checking pending alone avoids touching the D-cache
> after the flush.
> 

All valid points, thanks for the feedback.
-- 
Florian

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-11-13 21:52 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-13 19:08 [PATCH v6 0/4] MIPS: CI20: Enable SMP with two CPUs Florian Fainelli
2026-11-13 19:08 ` [PATCH v6 1/4] clk: ingenic: Poll JZ4780 CPU1 power status atomically Florian Fainelli
2026-11-13 19:08 ` [PATCH v6 2/4] MIPS: Skip generic IPI setup for platform-specific callbacks Florian Fainelli
2026-11-13 19:08 ` [PATCH v6 3/4] MIPS: Ingenic: Add XBurst SMP support Florian Fainelli
2026-11-13 19:40   ` sashiko-bot
2026-11-13 21:52     ` Florian Fainelli
2026-11-13 19:08 ` [PATCH v6 4/4] MIPS: CI20: Enable SMP with two CPUs Florian Fainelli
2026-11-13 20:51 ` (subset) [PATCH v6 0/4] " Brian Masney
2026-11-13 21:52   ` Florian Fainelli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox