The new SMP driver and the new cache driver.

81 views
Skip to first unread message

周琰杰 (Zhou Yanjie)

unread,
Dec 24, 2020, 3:38:48 AM12/24/20
to h...@goldelico.com, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
Hi Nikolaus, Paul, Riccardo,

These are the new patches, I have tested them on JZ4775, JZ4780, X1000,
X1830, X2000, and they can work normally for a long time. However, when
I run DMA TEST (built in the kernel) on JZ4780 (CI20 v1), dma0chan25 had
a failure once, but it did not appear again in dozens of subsequent tests,
you can pay attention on that when testing these patches.

The data of the cache driver test has not been completely sorted out, so
some data has not been written to the commit message. If you have collected
more representative data during test, you can supplement them.

In addition, according to thee documentation from Ingenic, the new cache
driver should also be applicable to JZ4770, JZ4760, JZ4755, JZ4750, JZ4740,
JZ4730, and JZ4725B, but I do not have the corresponding hardware for testing.
If you have these hardware, could you please help to test whether this driver
can work normally on them?

Merry Christmas!

Thanks and best regards!

周琰杰 (Zhou Yanjie)

unread,
Dec 24, 2020, 3:38:49 AM12/24/20
to h...@goldelico.com, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
1.On the hardware of CI20 v1, when the MSC0 clock is 50MHz, there is
a certain probability that the communication with the SD card will
be abnormal, and the file system will be damaged in severe cases.
Limiting the maximum MSC0 clock frequency to 25MHz can solve this
problem.
2.Add a new TCU channel as the percpu timer of core1, this is to
prepare for the subsequent SMP support. The newly added channel
will not adversely affect the current single-core state.

Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>
---
arch/mips/boot/dts/ingenic/ci20.dts | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/arch/mips/boot/dts/ingenic/ci20.dts b/arch/mips/boot/dts/ingenic/ci20.dts
index 8877c62..b420545 100644
--- a/arch/mips/boot/dts/ingenic/ci20.dts
+++ b/arch/mips/boot/dts/ingenic/ci20.dts
@@ -122,7 +122,7 @@
status = "okay";

bus-width = <4>;
- max-frequency = <50000000>;
+ max-frequency = <25000000>;

pinctrl-names = "default";
pinctrl-0 = <&pins_mmc0>;
@@ -525,10 +525,11 @@

&tcu {
/*
- * 750 kHz for the system timer and 3 MHz for the clocksource,
- * use channel #0 for the system timer, #1 for the clocksource.
+ * 750 kHz for the system timers and 3 MHz for the clocksources,
+ * use channel #0 and #1 for the per cpu system timers, and use
+ * channel #2 for the clocksource.
*/
assigned-clocks = <&tcu TCU_CLK_TIMER0>, <&tcu TCU_CLK_TIMER1>,
- <&tcu TCU_CLK_OST>;
- assigned-clock-rates = <750000>, <3000000>, <3000000>;
+ <&tcu TCU_CLK_TIMER2>, <&tcu TCU_CLK_OST>;
+ assigned-clock-rates = <750000>, <750000>, <3000000>, <3000000>;
};
--
2.7.4

周琰杰 (Zhou Yanjie)

unread,
Dec 24, 2020, 3:38:50 AM12/24/20
to h...@goldelico.com, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
According to the description of the document MD00090, when the IE
bits of the config4 register is 2 or 3, it supports TLBINV. The
difference is that when the value is 2, the TLBINV* instructions
only operate on one TLB entry, and when the value is 3, TLBINV*
instructions operate on entire MMU.

Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>
---
arch/mips/kernel/cpu-probe.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 049d04d..7793615 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -563,7 +563,8 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c)
config4 = read_c0_config4();

if (cpu_has_tlb) {
- if (((config4 & MIPS_CONF4_IE) >> 29) == 2)
+ if (((config4 & MIPS_CONF4_IE) >> 29) == 2 ||
+ ((config4 & MIPS_CONF4_IE) >> 29) == 3)
c->options |= MIPS_CPU_TLBINV;

/*
--
2.7.4

周琰杰 (Zhou Yanjie)

unread,
Dec 24, 2020, 3:38:51 AM12/24/20
to h...@goldelico.com, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
1.Add a new CPU_XBURST2 type for the MIPS32r5 compatible XBurst®2 CPU.
2.Add new macro for Ingenic specific cp0 register and corresponding bits.
3.Unify the format of Ingenic specific cp0 register and register bits.

Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>
---
arch/mips/generic/board-ingenic.c | 2 +-
arch/mips/include/asm/cpu-type.h | 1 +
arch/mips/include/asm/cpu.h | 4 ++--
arch/mips/include/asm/mipsregs.h | 14 ++++++++++----
arch/mips/kernel/cpu-probe.c | 6 +++---
arch/mips/kernel/idle.c | 1 +
arch/mips/mm/tlbex.c | 1 +
7 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/arch/mips/generic/board-ingenic.c b/arch/mips/generic/board-ingenic.c
index 0cec0be..dd855b7 100644
--- a/arch/mips/generic/board-ingenic.c
+++ b/arch/mips/generic/board-ingenic.c
@@ -108,7 +108,7 @@ static const struct platform_suspend_ops ingenic_pm_ops __maybe_unused = {

static int __init ingenic_pm_init(void)
{
- if (boot_cpu_type() == CPU_XBURST) {
+ if ((boot_cpu_type() == CPU_XBURST) || (boot_cpu_type() == CPU_XBURST2)) {
if (IS_ENABLED(CONFIG_PM_SLEEP))
suspend_set_ops(&ingenic_pm_ops);
_machine_halt = ingenic_halt;
diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h
index 3288cef..1b33da2 100644
--- a/arch/mips/include/asm/cpu-type.h
+++ b/arch/mips/include/asm/cpu-type.h
@@ -57,6 +57,7 @@ static inline int __pure __get_cpu_type(const int cpu_type)
#ifdef CONFIG_SYS_HAS_CPU_MIPS32_R5
case CPU_M5150:
case CPU_P5600:
+ case CPU_XBURST2:
#endif

#if defined(CONFIG_SYS_HAS_CPU_MIPS32_R2) || \
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index c9222cc..862d0d1 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -319,8 +319,8 @@ enum cpu_type_enum {
*/
CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350,
- CPU_BMIPS4380, CPU_BMIPS5000, CPU_XBURST, CPU_LOONGSON32, CPU_M14KC,
- CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K,
+ CPU_BMIPS4380, CPU_BMIPS5000, CPU_XBURST, CPU_XBURST2, CPU_LOONGSON32,
+ CPU_M14KC, CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K,
CPU_M5150, CPU_I6400, CPU_P6600, CPU_M6250,

/*
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index a0e8ae5..0783d99 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -738,10 +738,14 @@
#define MIPS_CONF7_AR (_ULCAST_(1) << 16)

/* Ingenic HPTLB off bits */
-#define XBURST_PAGECTRL_HPTLB_DIS 0xa9000000
+#define XBURST_PAGECTL_HPTLB_DIS 0xa9000000

/* Ingenic Config7 bits */
-#define MIPS_CONF7_BTB_LOOP_EN (_ULCAST_(1) << 4)
+#define XBURST_CONF7_BTB_LOOP_EN (_ULCAST_(1) << 4)
+
+/* Ingenic ErrCtl bits */
+#define XBURST_ERRCTL_WST_EN (_ULCAST_(1) << 29)
+#define XBURST_ERRCTL_WST_DIS (_ULCAST_(0) << 29)

/* Config7 Bits specific to MIPS Technologies. */

@@ -2034,8 +2038,10 @@ do { \
#define read_c0_brcm_sleepcount() __read_32bit_c0_register($22, 7)
#define write_c0_brcm_sleepcount(val) __write_32bit_c0_register($22, 7, val)

-/* Ingenic page ctrl register */
-#define write_c0_page_ctrl(val) __write_32bit_c0_register($5, 4, val)
+/* Ingenic XBurst SoCs specific registers */
+#define write_c0_ingenic_pagectl(val) __write_32bit_c0_register($5, 4, val)
+
+#define write_c0_ingenic_errctl(val) __write_32bit_c0_register($26, 0, val)

/*
* Macros to access the guest system control coprocessor
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 7793615..6ec7791 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -1817,7 +1817,7 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
* feature will cause BogoMIPS and lpj calculate in error.
* Set cp0 config7 bit 4 to disable this feature.
*/
- set_c0_config7(MIPS_CONF7_BTB_LOOP_EN);
+ set_c0_config7(XBURST_CONF7_BTB_LOOP_EN);

switch (c->processor_id & PRID_COMP_MASK) {

@@ -1840,7 +1840,7 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
* switch back to VTLB mode to prevent getting stuck.
*/
case PRID_COMP_INGENIC_D1:
- write_c0_page_ctrl(XBURST_PAGECTRL_HPTLB_DIS);
+ write_c0_ingenic_pagectl(XBURST_PAGECTL_HPTLB_DIS);
break;

default:
@@ -1858,7 +1858,7 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)

/* XBurst®2 with MXU2.1 SIMD ISA */
case PRID_IMP_XBURST2:
- c->cputype = CPU_XBURST;
+ c->cputype = CPU_XBURST2;
__cpu_name[cpu] = "Ingenic XBurst II";
break;

diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c
index 1aa2192..636e420 100644
--- a/arch/mips/kernel/idle.c
+++ b/arch/mips/kernel/idle.c
@@ -173,6 +173,7 @@ void __init check_wait(void)
case CPU_CAVIUM_OCTEON_PLUS:
case CPU_CAVIUM_OCTEON2:
case CPU_CAVIUM_OCTEON3:
+ case CPU_XBURST2:
case CPU_LOONGSON32:
case CPU_XLR:
case CPU_XLP:
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index a7521b8..f702c64 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -613,6 +613,7 @@ void build_tlb_write_entry(u32 **p, struct uasm_label **l,
break;

case CPU_XBURST:
+ case CPU_XBURST2:
tlbw(p);
uasm_i_nop(p);
break;
--
2.7.4

周琰杰 (Zhou Yanjie)

unread,
Dec 24, 2020, 3:38:52 AM12/24/20
to h...@goldelico.com, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
Forward port smp support from kernel 3.18.3 of CI20_linux
to upstream kernel 5.7.

Tested-by: H. Nikolaus Schaller <h...@goldelico.com>
Tested-by: Paul Boddie <pa...@boddie.org.uk>
Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>
Reviewed-by: Jiaxun Yang <jiaxu...@flygoat.com>
---
arch/mips/generic/Makefile | 1 +
arch/mips/generic/init.c | 4 +
arch/mips/include/asm/mach-ingenic/smp.h | 88 +++++++
arch/mips/ingenic/Kconfig | 3 +
arch/mips/ingenic/Makefile | 11 +
arch/mips/ingenic/smp-entry.S | 57 ++++
arch/mips/ingenic/smp.c | 430 +++++++++++++++++++++++++++++++
arch/mips/kernel/idle.c | 7 +-
8 files changed, 600 insertions(+), 1 deletion(-)
create mode 100644 arch/mips/include/asm/mach-ingenic/smp.h
create mode 100644 arch/mips/ingenic/Makefile
create mode 100644 arch/mips/ingenic/smp-entry.S
create mode 100644 arch/mips/ingenic/smp.c

diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile
index e37a59b..0e7194f 100644
--- a/arch/mips/generic/Makefile
+++ b/arch/mips/generic/Makefile
@@ -7,6 +7,7 @@
obj-y += init.o
obj-y += irq.o
obj-y += proc.o
+obj-y += ../ingenic/

obj-$(CONFIG_YAMON_DT_SHIM) += yamon-dt.o
obj-$(CONFIG_LEGACY_BOARD_SEAD3) += board-sead3.o
diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c
index 66a1933..88e509a 100644
--- a/arch/mips/generic/init.c
+++ b/arch/mips/generic/init.c
@@ -15,6 +15,7 @@
#include <asm/fw/fw.h>
#include <asm/irq_cpu.h>
#include <asm/machine.h>
+#include <asm/mach-ingenic/smp.h>
#include <asm/mips-cps.h>
#include <asm/prom.h>
#include <asm/smp-ops.h>
@@ -107,6 +108,9 @@ void __init plat_mem_setup(void)

fw_init_cmdline();
__dt_setup_arch((void *)fdt);
+
+ if (IS_ENABLED(CONFIG_SMP))
+ jz4780_smp_init();
}

void __init device_tree_init(void)
diff --git a/arch/mips/include/asm/mach-ingenic/smp.h b/arch/mips/include/asm/mach-ingenic/smp.h
new file mode 100644
index 00000000..321b647
--- /dev/null
+++ b/arch/mips/include/asm/mach-ingenic/smp.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2013, Paul Burton <paul....@imgtec.com>
+ * JZ4780 SMP definitions
+ */
+
+#ifndef __MIPS_ASM_MACH_JZ4740_SMP_H__
+#define __MIPS_ASM_MACH_JZ4740_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 read_c0_mailbox2() __read_32bit_c0_register($20, 2)
+#define write_c0_mailbox2(val) __write_32bit_c0_register($20, 2, val)
+
+#define read_c0_mailbox3() __read_32bit_c0_register($20, 3)
+#define write_c0_mailbox3(val) __write_32bit_c0_register($20, 3, val)
+
+#define smp_clr_pending(mask) do { \
+ unsigned int stat; \
+ stat = read_c0_corestatus(); \
+ stat &= ~((mask) & 0xff); \
+ write_c0_corestatus(stat); \
+ } while (0)
+
+/*
+ * Core Control register
+ */
+#define CORECTRL_SLEEP1M_SHIFT 17
+#define CORECTRL_SLEEP1M (_ULCAST_(0x1) << CORECTRL_SLEEP1M_SHIFT)
+#define CORECTRL_SLEEP0M_SHIFT 16
+#define CORECTRL_SLEEP0M (_ULCAST_(0x1) << CORECTRL_SLEEP0M_SHIFT)
+#define CORECTRL_RPC1_SHIFT 9
+#define CORECTRL_RPC1 (_ULCAST_(0x1) << CORECTRL_RPC1_SHIFT)
+#define CORECTRL_RPC0_SHIFT 8
+#define CORECTRL_RPC0 (_ULCAST_(0x1) << CORECTRL_RPC0_SHIFT)
+#define CORECTRL_SWRST1_SHIFT 1
+#define CORECTRL_SWRST1 (_ULCAST_(0x1) << CORECTRL_SWRST1_SHIFT)
+#define CORECTRL_SWRST0_SHIFT 0
+#define CORECTRL_SWRST0 (_ULCAST_(0x1) << CORECTRL_SWRST0_SHIFT)
+
+/*
+ * Core Status register
+ */
+#define CORESTATUS_SLEEP1_SHIFT 17
+#define CORESTATUS_SLEEP1 (_ULCAST_(0x1) << CORESTATUS_SLEEP1_SHIFT)
+#define CORESTATUS_SLEEP0_SHIFT 16
+#define CORESTATUS_SLEEP0 (_ULCAST_(0x1) << CORESTATUS_SLEEP0_SHIFT)
+#define CORESTATUS_IRQ1P_SHIFT 9
+#define CORESTATUS_IRQ1P (_ULCAST_(0x1) << CORESTATUS_IRQ1P_SHIFT)
+#define CORESTATUS_IRQ0P_SHIFT 8
+#define CORESTATUS_IRQ0P (_ULCAST_(0x1) << CORESTATUS_IRQ8P_SHIFT)
+#define CORESTATUS_MIRQ1P_SHIFT 1
+#define CORESTATUS_MIRQ1P (_ULCAST_(0x1) << CORESTATUS_MIRQ1P_SHIFT)
+#define CORESTATUS_MIRQ0P_SHIFT 0
+#define CORESTATUS_MIRQ0P (_ULCAST_(0x1) << CORESTATUS_MIRQ0P_SHIFT)
+
+/*
+ * Reset Entry & IRQ Mask register
+ */
+#define REIM_ENTRY_SHIFT 16
+#define REIM_ENTRY (_ULCAST_(0xffff) << REIM_ENTRY_SHIFT)
+#define REIM_IRQ1M_SHIFT 9
+#define REIM_IRQ1M (_ULCAST_(0x1) << REIM_IRQ1M_SHIFT)
+#define REIM_IRQ0M_SHIFT 8
+#define REIM_IRQ0M (_ULCAST_(0x1) << REIM_IRQ0M_SHIFT)
+#define REIM_MBOXIRQ1M_SHIFT 1
+#define REIM_MBOXIRQ1M (_ULCAST_(0x1) << REIM_MBOXIRQ1M_SHIFT)
+#define REIM_MBOXIRQ0M_SHIFT 0
+#define REIM_MBOXIRQ0M (_ULCAST_(0x1) << REIM_MBOXIRQ0M_SHIFT)
+
+extern void jz4780_smp_init(void);
+extern void jz4780_smp_wait_irqoff(void);
+extern void jz4780_secondary_cpu_entry(void);
+
+#endif /* __MIPS_ASM_MACH_JZ4740_SMP_H__ */
diff --git a/arch/mips/ingenic/Kconfig b/arch/mips/ingenic/Kconfig
index 043b539..6605a0e 100644
--- a/arch/mips/ingenic/Kconfig
+++ b/arch/mips/ingenic/Kconfig
@@ -8,6 +8,7 @@ config MACH_INGENIC_GENERIC
select MACH_JZ4775
select MACH_JZ4780
select MACH_X1000
+ select MACH_X1830

choice
prompt "Machine type"
@@ -69,9 +70,11 @@ config MACH_JZ4775

config MACH_JZ4780
bool
+ select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select MIPS_CPU_SCACHE
select SYS_HAS_CPU_MIPS32_R2
select SYS_SUPPORTS_HIGHMEM
+ select SYS_SUPPORTS_SMP

config MACH_X1000
bool
diff --git a/arch/mips/ingenic/Makefile b/arch/mips/ingenic/Makefile
new file mode 100644
index 00000000..4f90eee
--- /dev/null
+++ b/arch/mips/ingenic/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Ingenic JZ4740.
+#
+
+# Object file lists.
+CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
+
+# SMP support
+obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_SMP) += smp-entry.o
diff --git a/arch/mips/ingenic/smp-entry.S b/arch/mips/ingenic/smp-entry.S
new file mode 100644
index 00000000..20049a3
--- /dev/null
+++ b/arch/mips/ingenic/smp-entry.S
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2013, Paul Burton <paul....@imgtec.com>
+ * JZ4780 SMP entry point
+ */
+
+#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
+
+.extern jz4780_cpu_entry_sp
+.extern jz4780_cpu_entry_gp
+
+.section .text.smp-entry
+.balign 0x10000
+.set noreorder
+LEAF(jz4780_secondary_cpu_entry)
+ mtc0 zero, CP0_CAUSE
+
+ li t0, ST0_CU0
+ mtc0 t0, CP0_STATUS
+
+ /* cache setup */
+ li t0, KSEG0
+ ori t1, t0, CACHE_SIZE
+ mtc0 zero, CP0_TAGLO, 0
+1: cache Index_Store_Tag_I, 0(t0)
+ cache Index_Store_Tag_D, 0(t0)
+ bne t0, t1, 1b
+ addiu t0, t0, CACHE_LINESIZE
+
+ /* kseg0 cache attribute */
+ mfc0 t0, CP0_CONFIG, 0
+ ori t0, t0, CONF_CM_CACHABLE_NONCOHERENT
+ mtc0 t0, CP0_CONFIG, 0
+
+ /* pagemask */
+ mtc0 zero, CP0_PAGEMASK, 0
+
+ /* retrieve sp */
+ la t0, jz4780_cpu_entry_sp
+ lw sp, 0(t0)
+
+ /* retrieve gp */
+ la t0, jz4780_cpu_entry_gp
+ lw gp, 0(t0)
+
+ /* jump to the kernel in kseg0 */
+ la t0, smp_bootstrap
+ jr t0
+ nop
+ END(jz4780_secondary_cpu_entry)
diff --git a/arch/mips/ingenic/smp.c b/arch/mips/ingenic/smp.c
new file mode 100644
index 00000000..871af45
--- /dev/null
+++ b/arch/mips/ingenic/smp.c
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2013, Paul Burton <paul....@imgtec.com>
+ * JZ4780 SMP
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/sched.h>
+#include <linux/sched/task_stack.h>
+#include <linux/smp.h>
+#include <linux/tick.h>
+#include <asm/mach-ingenic/smp.h>
+#include <asm/r4kcache.h>
+#include <asm/smp-ops.h>
+
+static struct clk *cpu_clock_gates[CONFIG_NR_CPUS] = { NULL };
+
+u32 jz4780_cpu_entry_sp;
+u32 jz4780_cpu_entry_gp;
+
+static struct cpumask cpu_running;
+
+static DEFINE_SPINLOCK(smp_lock);
+
+#define XBURST_TAGLO_DIRTY_MASK 0xc
+
+static inline __always_inline notrace void wback_dcache(void)
+{
+ unsigned long start = INDEX_BASE;
+ unsigned long end = start + current_cpu_data.dcache.waysize;
+ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
+ unsigned long ws_end =
+ current_cpu_data.dcache.ways << current_cpu_data.dcache.waybit;
+ unsigned long ws, addr, tmp;
+
+ /*
+ * Doing a writeback/invalidate on the whole cache has a significant
+ * performance cost. In this loop we instead only writeback/invalidate
+ * cache lines which are marked dirty. To do this we load the tag at
+ * each index and check the (Ingenic-specific) dirty bits, and only
+ * perform the operation if they are set. There is still a performance
+ * cost to this but it is nowhere near as high as blasting the whole
+ * cache.
+ */
+ for (ws = 0; ws < ws_end; ws += ws_inc) {
+ for (addr = start; addr < end; addr += cpu_dcache_line_size()) {
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set noreorder \n"
+ " .set mips3 \n"
+ " cache %2, (%1) \n"
+ " ehb \n"
+ " mfc0 %0, " __stringify(CP0_TAGLO) " \n"
+ " and %0, %0, %3 \n"
+ " beq $0, %0, 1f \n"
+ " nop \n"
+ " cache %4, (%1) \n"
+ "1: .set pop \n"
+ : "=&r" (tmp)
+ : "r" (addr | ws),
+ "i" (Index_Load_Tag_D),
+ "i" (XBURST_TAGLO_DIRTY_MASK),
+ "i" (Index_Writeback_Inv_D));
+ }
+ }
+}
+
+/*
+ * The Ingenic XBurst SMP variant has to write back dirty cache lines before
+ * executing wait. The CPU & cache clock will be gated until we return from
+ * the wait, and if another core attempts to access data from our data cache
+ * during this time then it will lock up.
+ */
+void jz4780_smp_wait_irqoff(void)
+{
+ unsigned long pending = read_c0_cause() & read_c0_status() & CAUSEF_IP;
+
+ /*
+ * Going to idle has a significant overhead due to the cache flush so
+ * try to avoid it if we'll immediately be woken again due to an IRQ.
+ */
+ if (!need_resched() && !pending) {
+ wback_dcache();
+
+ __asm__(
+ " .set push \n"
+ " .set mips3 \n"
+ " sync \n"
+ " wait \n"
+ " .set pop \n");
+ }
+
+ local_irq_enable();
+}
+
+static irqreturn_t mbox_handler(int irq, void *dev_id)
+{
+ int cpu = smp_processor_id();
+ u32 action, status;
+
+ spin_lock(&smp_lock);
+
+ switch (cpu) {
+ case 0:
+ action = read_c0_mailbox0();
+ write_c0_mailbox0(0);
+ break;
+ case 1:
+ action = read_c0_mailbox1();
+ write_c0_mailbox1(0);
+ break;
+ case 2:
+ action = read_c0_mailbox2();
+ write_c0_mailbox2(0);
+ break;
+ case 3:
+ action = read_c0_mailbox3();
+ write_c0_mailbox3(0);
+ break;
+ default:
+ panic("unhandled cpu %d!", cpu);
+ }
+
+ /* clear pending mailbox interrupt */
+ status = read_c0_corestatus();
+ status &= ~(CORESTATUS_MIRQ0P << cpu);
+ write_c0_corestatus(status);
+
+ 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 jz4780_smp_setup(void)
+{
+ struct device_node *cpu_node;
+ u32 addr, reim;
+ int cpu = 0;
+
+ reim = read_c0_reim();
+
+ for_each_of_cpu_node(cpu_node) {
+ __cpu_number_map[cpu] = cpu;
+ __cpu_logical_map[cpu] = cpu;
+ set_cpu_possible(cpu++, true);
+ }
+
+ /* mask mailbox interrupts for this core */
+ reim &= ~REIM_MBOXIRQ0M;
+ write_c0_reim(reim);
+
+ /* clear mailboxes & pending mailbox IRQs */
+ write_c0_mailbox0(0);
+ write_c0_mailbox1(0);
+ write_c0_mailbox2(0);
+ write_c0_mailbox3(0);
+ write_c0_corestatus(0);
+
+ /* set reset entry point */
+ addr = KSEG1ADDR((u32)&jz4780_secondary_cpu_entry);
+ WARN_ON(addr & ~REIM_ENTRY);
+ reim &= ~REIM_ENTRY;
+ reim |= addr & REIM_ENTRY;
+
+ /* unmask mailbox interrupts for this core */
+ reim |= REIM_MBOXIRQ0M;
+ write_c0_reim(reim);
+ set_c0_status(STATUSF_IP3);
+ irq_enable_hazard();
+
+ cpumask_set_cpu(cpu, &cpu_running);
+}
+
+static void jz4780_smp_prepare_cpus(unsigned int max_cpus)
+{
+ struct device_node *cpu_node;
+ unsigned cpu, ctrl;
+ int err;
+
+ /* setup the mailbox IRQ */
+ err = request_irq(MIPS_CPU_IRQ_BASE + 3, mbox_handler,
+ IRQF_PERCPU | IRQF_NO_THREAD, "core mailbox", NULL);
+ if (err)
+ pr_err("request_irq() on core mailbox failed\n");
+
+ ctrl = read_c0_corectrl();
+
+ for_each_of_cpu_node(cpu_node) {
+ cpu = of_cpu_node_to_id(cpu_node);
+ if (cpu < 0) {
+ pr_err("Failed to read index of %s\n",
+ cpu_node->full_name);
+ continue;
+ }
+
+ /* use reset entry point from REIM register */
+ ctrl |= CORECTRL_RPC0 << cpu;
+
+ cpu_clock_gates[cpu] = of_clk_get(cpu_node, 0);
+ if (IS_ERR(cpu_clock_gates[cpu])) {
+ cpu_clock_gates[cpu] = NULL;
+ continue;
+ }
+ }
+
+ write_c0_corectrl(ctrl);
+}
+
+static int jz4780_boot_secondary(int cpu, struct task_struct *idle)
+{
+ unsigned long flags;
+ int err;
+ u32 ctrl;
+
+ spin_lock_irqsave(&smp_lock, flags);
+
+ /* ensure the core is in reset */
+ ctrl = read_c0_corectrl();
+ ctrl |= CORECTRL_SWRST0 << cpu;
+ write_c0_corectrl(ctrl);
+
+ /* ungate core clock */
+ if (cpu_clock_gates[cpu]) {
+ err = clk_prepare(cpu_clock_gates[cpu]);
+ if (err)
+ pr_err("Failed to prepare CPU clock gate\n");
+
+ err = clk_enable(cpu_clock_gates[cpu]);
+ if (err)
+ pr_err("Failed to ungate core clock\n");
+ }
+
+ /* set entry sp/gp register values */
+ jz4780_cpu_entry_sp = __KSTK_TOS(idle);
+ jz4780_cpu_entry_gp = (u32)task_thread_info(idle);
+ smp_wmb();
+
+ /* take the core out of reset */
+ ctrl &= ~(CORECTRL_SWRST0 << cpu);
+ write_c0_corectrl(ctrl);
+
+ cpumask_set_cpu(cpu, &cpu_running);
+
+ spin_unlock_irqrestore(&smp_lock, flags);
+
+ return 0;
+}
+
+static void jz4780_init_secondary(void)
+{
+}
+
+static void jz4780_smp_finish(void)
+{
+ u32 reim;
+
+ spin_lock(&smp_lock);
+
+ /* unmask mailbox interrupts for this core */
+ reim = read_c0_reim();
+ reim |= REIM_MBOXIRQ0M << smp_processor_id();
+ write_c0_reim(reim);
+
+ spin_unlock(&smp_lock);
+
+ /* unmask interrupts for this core */
+ change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP2 |
+ STATUSF_IP1 | STATUSF_IP0);
+ irq_enable_hazard();
+
+ /* force broadcast timer */
+ tick_broadcast_force();
+}
+
+static void jz4780_send_ipi_single_locked(int cpu, unsigned int action)
+{
+ u32 mbox;
+
+ switch (cpu) {
+ case 0:
+ mbox = read_c0_mailbox0();
+ write_c0_mailbox0(mbox | action);
+ break;
+ case 1:
+ mbox = read_c0_mailbox1();
+ write_c0_mailbox1(mbox | action);
+ break;
+ case 2:
+ mbox = read_c0_mailbox2();
+ write_c0_mailbox2(mbox | action);
+ break;
+ case 3:
+ mbox = read_c0_mailbox3();
+ write_c0_mailbox3(mbox | action);
+ break;
+ default:
+ panic("unhandled cpu %d!", cpu);
+ }
+}
+
+static void jz4780_send_ipi_single(int cpu, unsigned int action)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&smp_lock, flags);
+ jz4780_send_ipi_single_locked(cpu, action);
+ spin_unlock_irqrestore(&smp_lock, flags);
+}
+
+static void jz4780_send_ipi_mask(const struct cpumask *mask,
+ unsigned int action)
+{
+ unsigned long flags;
+ int cpu;
+
+ spin_lock_irqsave(&smp_lock, flags);
+
+ for_each_cpu(cpu, mask)
+ jz4780_send_ipi_single_locked(cpu, action);
+
+ spin_unlock_irqrestore(&smp_lock, flags);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+int jz4780_cpu_disable(void)
+{
+ unsigned int cpu = smp_processor_id();
+ unsigned int status;
+
+ local_irq_disable();
+
+ set_cpu_online(cpu, false);
+
+ spin_lock(&smp_lock);
+ status = read_c0_reim();
+ if (status & (1 << (cpu + 8))) {
+ status &= ~(1 << (cpu + 8));
+ status |= (1 << 8); /* irq to cpu0 */
+ write_c0_reim(status);
+ }
+
+ spin_unlock(&smp_lock);
+
+ return 0;
+}
+
+void jz4780_cpu_die(unsigned int cpu)
+{
+ unsigned long flags;
+ unsigned int status;
+
+ local_irq_save(flags);
+
+ cpumask_clear_cpu(cpu, &cpu_running);
+
+ wmb();
+ do {
+ status = read_c0_corestatus();
+ } while (!(status & (1 << (cpu + 16))));
+
+ clk_disable_unprepare(cpu_clock_gates[cpu]);
+
+ local_irq_restore(flags);
+}
+
+void __play_dead(void)
+{
+ __asm__ __volatile__ (
+ " .set push \n"
+ " .set mips3 \n"
+ " sync \n"
+ " wait \n"
+ " .set pop \n");
+}
+
+void play_dead(void) {
+ void (*do_play_dead)(void) = (void (*)(void)) KSEG1ADDR(__play_dead);
+ unsigned int cpu = smp_processor_id();
+
+
+ local_irq_disable();
+
+ switch (cpu) {
+ case 0:
+ write_c0_mailbox0(0);
+ break;
+ case 1:
+ write_c0_mailbox1(0);
+ break;
+ }
+
+ smp_clr_pending(1 << cpu);
+
+ while(1) {
+ while(cpumask_test_cpu(cpu, &cpu_running))
+ ;
+ blast_icache32();
+ blast_dcache32();
+
+ do_play_dead();
+ }
+}
+#endif
+
+static struct plat_smp_ops jz4780_smp_ops = {
+ .send_ipi_single = jz4780_send_ipi_single,
+ .send_ipi_mask = jz4780_send_ipi_mask,
+ .init_secondary = jz4780_init_secondary,
+ .smp_finish = jz4780_smp_finish,
+ .boot_secondary = jz4780_boot_secondary,
+ .smp_setup = jz4780_smp_setup,
+ .prepare_cpus = jz4780_smp_prepare_cpus,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_disable = jz4780_cpu_disable,
+ .cpu_die = jz4780_cpu_die,
+#endif
+};
+
+void __init jz4780_smp_init(void)
+{
+ register_smp_ops(&jz4780_smp_ops);
+}
diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c
index 18e69eb..1aa2192 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/mach-ingenic/smp.h>

/*
* Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
@@ -172,7 +173,6 @@ void __init check_wait(void)
case CPU_CAVIUM_OCTEON_PLUS:
case CPU_CAVIUM_OCTEON2:
case CPU_CAVIUM_OCTEON3:
- case CPU_XBURST:
case CPU_LOONGSON32:
case CPU_XLR:
case CPU_XLP:
@@ -247,6 +247,11 @@ void __init check_wait(void)
cpu_wait = r4k_wait;
*/
break;
+ case CPU_XBURST:
+ if (IS_ENABLED(CONFIG_SMP))
+ cpu_wait = jz4780_smp_wait_irqoff;
+ else
+ cpu_wait = r4k_wait;
default:
break;
}
--
2.7.4

周琰杰 (Zhou Yanjie)

unread,
Dec 24, 2020, 3:38:53 AM12/24/20
to h...@goldelico.com, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
Ingenic XBurst®1 and XBurst®2 CPUs avoid hazard through hardware,
so no additional ehb instructions are required.

Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>
---
arch/mips/include/asm/hazards.h | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/mips/include/asm/hazards.h b/arch/mips/include/asm/hazards.h
index f855478..332a5df 100644
--- a/arch/mips/include/asm/hazards.h
+++ b/arch/mips/include/asm/hazards.h
@@ -24,7 +24,8 @@
*/
#if (defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR5) || \
defined(CONFIG_CPU_MIPSR6)) && \
- !defined(CONFIG_CPU_CAVIUM_OCTEON) && !defined(CONFIG_CPU_LOONGSON64)
+ !defined(CONFIG_CPU_CAVIUM_OCTEON) && !defined(CONFIG_CPU_LOONGSON64) && \
+ !defined(CONFIG_MACH_INGENIC)

/*
* MIPSR2 defines ehb for hazard avoidance
@@ -160,7 +161,8 @@ do { \

#elif defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \
defined(CONFIG_CPU_LOONGSON2EF) || defined(CONFIG_CPU_LOONGSON64) || \
- defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_R5500) || defined(CONFIG_CPU_XLR)
+ defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_R5500) || defined(CONFIG_CPU_XLR) || \
+ defined(CONFIG_MACH_INGENIC)

/*
* R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
--
2.7.4

周琰杰 (Zhou Yanjie)

unread,
Dec 24, 2020, 3:38:55 AM12/24/20
to h...@goldelico.com, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it, Alex Smith
The JZ4780 has a high overhead to executing a MIPS wait on SMP, as a
core must flush out dirty cache lines from its data cache before doing
so. This is because the core clock is gated during a wait and if the
other core tries to access a dirty line from the waiting core's cache,
it will lock up.

To mitigate some of this impact, this driver provides a simple polling
top level idle state, to try to avoid the cache flushing overhead when
the wait will only be short. The second level state is implemented with
the MIPS wait instruction.

This patch first found in the github repository of CI20, the original
author is Alex Smith. Because there is a chance to cause kernel hang
scenarios which can occur within hours or even within days, so this
patch was abandoned, but now it is determined that this is not the
problem caused by this patch, but caused by the cache driver. With
the new Ingenic specific cache driver, it has been working properly
on CI20 v1 for more than one week.

Signed-off-by: Alex Smith <alex....@imgtec.com>
Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>
---
drivers/cpuidle/Kconfig.mips | 8 +++++
drivers/cpuidle/Makefile | 1 +
drivers/cpuidle/cpuidle-jz4780.c | 74 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 83 insertions(+)
create mode 100755 drivers/cpuidle/cpuidle-jz4780.c

diff --git a/drivers/cpuidle/Kconfig.mips b/drivers/cpuidle/Kconfig.mips
index c3c011a..4a55d24 100644
--- a/drivers/cpuidle/Kconfig.mips
+++ b/drivers/cpuidle/Kconfig.mips
@@ -16,3 +16,11 @@ config MIPS_CPS_CPUIDLE
Processing System (CPS) architecture. In order to make use of
the deepest idle states you will need to ensure that you are
also using the CONFIG_MIPS_CPS SMP implementation.
+
+config MIPS_JZ4780_CPUIDLE
+ bool "CPU Idle driver for Ingenic JZ4780"
+ depends on MACH_JZ4780 && SMP
+ default y
+ help
+ Select this option to enable CPU idle state management through
+ cpuidle for Ingenic JZ4780 platforms.
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 26bbc5e..1dd372f 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_ARM_QCOM_SPM_CPUIDLE) += cpuidle-qcom-spm.o
###############################################################################
# MIPS drivers
obj-$(CONFIG_MIPS_CPS_CPUIDLE) += cpuidle-cps.o
+obj-$(CONFIG_MIPS_JZ4780_CPUIDLE) += cpuidle-jz4780.o

###############################################################################
# POWERPC drivers
diff --git a/drivers/cpuidle/cpuidle-jz4780.c b/drivers/cpuidle/cpuidle-jz4780.c
new file mode 100755
index 00000000..2025de4
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-jz4780.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * JZ4780 CPU idle driver
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex....@imgtec.com>
+ * Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>
+ */
+
+#include <linux/cpuidle.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/sched/idle.h>
+
+#include <asm/idle.h>
+#include <asm/mipsregs.h>
+
+/*
+ * The JZ4780 has a high overhead to entering just the basic MIPS wait on SMP,
+ * due to the requirement to flush out dirty lines from the dcache before
+ * waiting. Therefore, we try to mitigate this overhead by using a simple
+ * polling loop for short waits.
+ */
+static int jz4780_cpuidle_poll_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ if (!current_set_polling_and_test())
+ while (!need_resched() && !(read_c0_cause() & read_c0_status() & CAUSEF_IP))
+ cpu_relax();
+
+ current_clr_polling();
+ local_irq_enable();
+
+ return index;
+}
+
+static struct cpuidle_driver jz4780_cpuidle_driver = {
+ .name = "jz4780_cpuidle",
+ .owner = THIS_MODULE,
+ .states = {
+ {
+ .enter = jz4780_cpuidle_poll_enter,
+ .exit_latency = 1,
+ .target_residency = 1,
+ .power_usage = UINT_MAX,
+ .name = "poll",
+ .desc = "polling loop",
+ },
+ {
+ .enter = mips_cpuidle_wait_enter,
+ .exit_latency = 50,
+ .target_residency = 300,
+ .power_usage = UINT_MAX,
+ .name = "wait",
+ .desc = "MIPS wait",
+ },
+ },
+ .state_count = 2,
+};
+
+static int __init jz4780_cpuidle_init(void)
+{
+ int ret;
+
+ ret = cpuidle_register(&jz4780_cpuidle_driver, NULL);
+ if (ret) {
+ pr_err("Failed to register JZ4780 idle driver: %d\n", ret);
+ return ret;
+ }
+
+ pr_info("JZ4780 idle driver registered\n");
+
+ return 0;
+}
+device_initcall(jz4780_cpuidle_init);
--
2.7.4

周琰杰 (Zhou Yanjie)

unread,
Dec 24, 2020, 3:38:55 AM12/24/20
to h...@goldelico.com, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
1.Ingenic XBurst®2's TLBINV* instructions operate on entire MMU, so the
"local_flush_tlb_all()" function can be optimized accordingly to avoid
unnecessary overhead.
2.For non-Loongson processors, existing code calls to "flush_micro_tlb()"
and "flush_micro_tlb_vm()" will introduce additional overhead. In order
to avoid unnecessary additional overhead caused by calling these two
functions on other normal MIPS processors, macro control switches are
added to avoid this problem.

Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>
---
arch/mips/mm/tlb-r4k.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 1b939ab..5c7bd79 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -55,7 +55,7 @@ void local_flush_tlb_all(void)
{
unsigned long flags;
unsigned long old_ctx;
- int entry, ftlbhighset;
+ int entry;

local_irq_save(flags);
/* Save old context and create impossible VPN2 value */
@@ -71,6 +71,8 @@ void local_flush_tlb_all(void)
* If there are any wired entries, fall back to iterating
*/
if (cpu_has_tlbinv && !entry) {
+#ifndef CONFIG_MACH_X2000
+ int ftlbhighset;
if (current_cpu_data.tlbsizevtlb) {
write_c0_index(0);
mtc0_tlbw_hazard();
@@ -85,6 +87,9 @@ void local_flush_tlb_all(void)
mtc0_tlbw_hazard();
tlbinvf(); /* invalidate one FTLB set */
}
+#else
+ tlbinvf(); /* invalide FTLB/VTLB set */
+#endif
} else {
while (entry < current_cpu_data.tlbsize) {
/* Make sure all entries differ. */
@@ -98,7 +103,9 @@ void local_flush_tlb_all(void)
tlbw_use_hazard();
write_c0_entryhi(old_ctx);
htw_start();
+#if defined(CONFIG_MACH_LOONGSON2EF) || defined(CONFIG_MACH_LOONGSON64)
flush_micro_tlb();
+#endif
local_irq_restore(flags);
}
EXPORT_SYMBOL(local_flush_tlb_all);
@@ -158,7 +165,9 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
} else {
drop_mmu_context(mm);
}
+#if defined(CONFIG_MACH_LOONGSON2EF) || defined(CONFIG_MACH_LOONGSON64)
flush_micro_tlb();
+#endif
local_irq_restore(flags);
}
}
@@ -204,7 +213,9 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
} else {
local_flush_tlb_all();
}
+#if defined(CONFIG_MACH_LOONGSON2EF) || defined(CONFIG_MACH_LOONGSON64)
flush_micro_tlb();
+#endif
local_irq_restore(flags);
}

@@ -247,7 +258,9 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
if (cpu_has_mmid)
write_c0_memorymapid(old_mmid);
htw_start();
+#if defined(CONFIG_MACH_LOONGSON2EF) || defined(CONFIG_MACH_LOONGSON64)
flush_micro_tlb_vm(vma);
+#endif
local_irq_restore(flags);
}
}
@@ -281,7 +294,9 @@ void local_flush_tlb_one(unsigned long page)
}
write_c0_entryhi(oldpid);
htw_start();
+#if defined(CONFIG_MACH_LOONGSON2EF) || defined(CONFIG_MACH_LOONGSON64)
flush_micro_tlb();
+#endif
local_irq_restore(flags);
}

@@ -372,7 +387,9 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
}
tlbw_use_hazard();
htw_start();
+#if defined(CONFIG_MACH_LOONGSON2EF) || defined(CONFIG_MACH_LOONGSON64)
flush_micro_tlb_vm(vma);
+#endif
local_irq_restore(flags);
}

--
2.7.4

周琰杰 (Zhou Yanjie)

unread,
Dec 24, 2020, 3:38:57 AM12/24/20
to h...@goldelico.com, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
Refresh defconfig of CI20 to enable cpuidle.

Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>
---
arch/mips/configs/ci20_defconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/mips/configs/ci20_defconfig b/arch/mips/configs/ci20_defconfig
index 138780d..65ea32923 100644
--- a/arch/mips/configs/ci20_defconfig
+++ b/arch/mips/configs/ci20_defconfig
@@ -29,6 +29,7 @@ CONFIG_SMP=y
CONFIG_HOTPLUG_CPU=y
CONFIG_NR_CPUS=2
CONFIG_HZ_100=y
+CONFIG_CPU_IDLE=y
# CONFIG_SECCOMP is not set
# CONFIG_SUSPEND is not set
CONFIG_MODULES=y
--
2.7.4

Paul Boddie

unread,
Dec 24, 2020, 6:55:28 AM12/24/20
to 周琰杰 (Zhou Yanjie), h...@goldelico.com, mips-creat...@googlegroups.com, riccardo...@libero.it
On Thursday, 24 December 2020 09:38:08 CET 周琰杰 (Zhou Yanjie) wrote:
> Hi Nikolaus, Paul, Riccardo,
>
> These are the new patches, I have tested them on JZ4775, JZ4780, X1000,
> X1830, X2000, and they can work normally for a long time. However, when
> I run DMA TEST (built in the kernel) on JZ4780 (CI20 v1), dma0chan25 had
> a failure once, but it did not appear again in dozens of subsequent tests,
> you can pay attention on that when testing these patches.

I noticed a remark in patch 04/13 about the UserLocal register not being
present in XBurst1. I had thought that this was actually used in the port of
Fiasco to the CI20, but now that I review that code, I see that the register
is only mentioned when dealing with virtualisation (MIPS VZ) features (for
other MIPS CPUs). Maybe I had just noted its existence and had thought to
investigate further.

> The data of the cache driver test has not been completely sorted out, so
> some data has not been written to the commit message. If you have collected
> more representative data during test, you can supplement them.
>
> In addition, according to thee documentation from Ingenic, the new cache
> driver should also be applicable to JZ4770, JZ4760, JZ4755, JZ4750, JZ4740,
> JZ4730, and JZ4725B, but I do not have the corresponding hardware for
> testing. If you have these hardware, could you please help to test whether
> this driver can work normally on them?

This looks like some great work in investigating the hardware capabilities and
applying that knowledge to Linux. There are probably so many small details
that are revealed in the documentation that can be so easy to overlook when
supporting this hardware.

(I probably tripped over some minor details when modifying Fiasco for the
JZ4730, but this work is at a completely different level, and I feel a bit
guilty for taking the easiest path and assuming that there wouldn't be too
many differences from classic MIPS implementations.)

I'll have to set aside some time to look at this more closely and to see if
the code can be deployed on the JZ4730 and JZ4740 (more accurately, the JZ4720
in the Ben NanoNote). Hopefully, our other efforts will make this more
convenient.

Many thanks for all this hard work!

> Merry Christmas!

Merry Christmas to you, too! :-)

Paul


H. Nikolaus Schaller

unread,
Dec 26, 2020, 3:20:06 AM12/26/20
to "周琰杰 (Zhou Yanjie)", mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
Hi,

> Am 24.12.2020 um 09:38 schrieb 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>:
>
> Hi Nikolaus, Paul, Riccardo,
>
> These are the new patches, I have tested them on JZ4775, JZ4780, X1000,
> X1830, X2000,

Thank you very much again for this XMAS present!

I also have some progress present for the jz4730. Have - almost - fixed the I2C driver.

> and they can work normally for a long time. However, when
> I run DMA TEST (built in the kernel) on JZ4780 (CI20 v1), dma0chan25 had
> a failure once, but it did not appear again in dozens of subsequent tests,
> you can pay attention on that when testing these patches.
>
> The data of the cache driver test has not been completely sorted out, so
> some data has not been written to the commit message. If you have collected
> more representative data during test, you can supplement them.
>
> In addition, according to thee documentation from Ingenic, the new cache
> driver should also be applicable to JZ4770, JZ4760, JZ4755, JZ4750, JZ4740,
> JZ4730, and JZ4725B, but I do not have the corresponding hardware for testing.
> If you have these hardware, could you please help to test whether this driver
> can work normally on them?

I tried to git am this series, but what is the base to start with?

>
> Merry Christmas!

>
> Thanks and best regards!


Thanks and same to you!

Best regards,
Nikolaus

Zhou Yanjie

unread,
Dec 26, 2020, 5:01:16 AM12/26/20
to H. Nikolaus Schaller, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
Hi Nikolaus,
I tested it on 5.10.0 and 5.10.1, both can work normally.

H. Nikolaus Schaller

unread,
Dec 26, 2020, 6:41:45 AM12/26/20
to Zhou Yanjie, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
Hi,
I just get this:

iMac:master hns$ git checkout v5.10
Note: switching to 'v5.10'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

git switch -c <new-branch-name>

Or undo this operation with:

git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 2c85ebc57b3e Linux 5.10
iMac:master hns$ git am 0001-\[PATCH\ 01_13\]\ MIPS_\ JZ4780_\ Introduce\ SMP\ support..eml
Applying: MIPS: JZ4780: Introduce SMP support.
error: patch failed: arch/mips/ingenic/Kconfig:8
error: arch/mips/ingenic/Kconfig: patch does not apply
Patch failed at 0001 MIPS: JZ4780: Introduce SMP support.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
iMac:master hns$

iMac:master hns$ git am --show-current-patch=diff
---

... cut ...

+
+#endif /* __MIPS_ASM_MACH_JZ4740_SMP_H__ */
diff --git a/arch/mips/ingenic/Kconfig b/arch/mips/ingenic/Kconfig
index 043b539..6605a0e 100644
--- a/arch/mips/ingenic/Kconfig
+++ b/arch/mips/ingenic/Kconfig
@@ -8,6 +8,7 @@ config MACH_INGENIC_GENERIC
select MACH_JZ4775
select MACH_JZ4780
select MACH_X1000
+ select MACH_X1830

choice
prompt "Machine type"
@@ -69,9 +70,11 @@ config MACH_JZ4775
^C

iMac:master hns$ head -10 arch/mips/ingenic/Kconfig
# SPDX-License-Identifier: GPL-2.0

config MACH_INGENIC_GENERIC
bool
select MACH_INGENIC
select MACH_JZ4740
select MACH_JZ4770
select MACH_JZ4780
select MACH_X1000

iMac:master hns$

So it appears that your first patch assumes a select (CONFIG_)MACH_JZ4775
to be in arch/mips/ingenic/Kconfig which is not the case for official
kernels.

Do you have a git repo to cherry-pick/pull from?

BR and thanks,
Nikolaus

Zhou Yanjie

unread,
Dec 28, 2020, 2:17:17 AM12/28/20
to H. Nikolaus Schaller, mips-creat...@googlegroups.com, pa...@boddie.org.uk, riccardo...@libero.it
Hi Nikolaus,
This is my repo: https://github.com/XBurst/Linux-XBurst

or you can use this: https://github.com/Ingenic-community/Linux-XBurst

But the 5.10 patches have not been sorted and uploaded, tomorrow I will
make a patch based on 5.10.3 and send to you.

Thanks and best regards!


> BR and thanks,
> Nikolaus

H. Nikolaus Schaller

unread,
Jan 6, 2021, 12:32:36 PM1/6/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi,

> Am 28.12.2020 um 08:16 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>
>>
>> So it appears that your first patch assumes a select (CONFIG_)MACH_JZ4775
>> to be in arch/mips/ingenic/Kconfig which is not the case for official
>> kernels.
>>
>> Do you have a git repo to cherry-pick/pull from?
>
>
> This is my repo: https://github.com/XBurst/Linux-XBurst
>
> or you can use this: https://github.com/Ingenic-community/Linux-XBurst
>
> But the 5.10 patches have not been sorted and uploaded, tomorrow I will make a patch based on 5.10.3 and send to you.
>
> Thanks and best regards!

I haven't followed up on this yet but I managed to fix the CI20 HDMI driver
on v5.11-rc1. The problem was small. 5.11-rc1 introduced a new pixel format-table
to support different formats for two planes. Since jz4780 HDMI is not upstream,
there was no format table provided for the jz4780...

I just found it by accident trying to cherry-pick all changes and accidentially
fixe the merge conflict by adding the jz4770 table to the jz4780. I am not sure
if the table is complete but that can be discussed when upstreaming our HDMI
solution one day.

So it now works and I can switch to v5.11-rc2 and start to test any new SMP code.

BR,
Nikolaus

H. Nikolaus Schaller

unread,
Jan 7, 2021, 9:31:54 AM1/7/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi,
Ok, I did a new attempt.

I could now git am all patches except [PATCH 10_13] MIPS_ mm_ Add Ingenic XBurst SoCs specific cache driver.
on top of latest linux-next and cherry-pick them onto letux-5.11-rc2. 10/13 simply
did fail to apply without conflicts to resolve so I did skip it.

This kernel now boots with 2 cores (incl. HDMI) and no immediately visible
issues.

So what is the missing patch doing and improve? Is it necessary?
Where can I find a version that applies to linux/next?

Please let me know how I can help more testing.

BR and thanks,
Nikolaus

H. Nikolaus Schaller

unread,
Jan 7, 2021, 12:48:02 PM1/7/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Well, after letting it idle (Ethernet connected) for a while I found the board
with heartbeat LED no longer blinking. HDMI did still show the last image. Console
did buffer something and echo ctrl-C as ^C but nothing else.

BR,
Nikolaus

Zhou Yanjie

unread,
Jan 13, 2021, 10:02:01 AM1/13/21
to H. Nikolaus Schaller, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hello Riccardo, Nikolaus, Paul,

I'm very sorry, because the college is approaching the end of the
semester recently, I was temporarily assigned some tasks, so I failed to
update the patch in time, I will make a new patch based on 5.10.7 tomorrow.

Thanks and best regards!

On 2021/1/7 下午10:31, H. Nikolaus Schaller wrote:
> Hi,
>
>> Am 06.01.2021 um 18:32 schrieb H. Nikolaus Schaller <h...@goldelico.com>:
>> I

Zhou Yanjie

unread,
Jan 14, 2021, 11:31:29 AM1/14/21
to H. Nikolaus Schaller, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hello Nikolaus,

Attached are the new patches, based on kernel 5.10.7.

Thanks and best regards!
0001-MIPS-JZ4780-Introduce-SMP-support.patch
0010-MIPS-mm-Add-Ingenic-XBurst-SoCs-specific-cache-drive.patch
0011-MIPS-mm-Remove-code-that-is-no-longer-needed.patch
0012-cpuidle-JZ4780-Add-Ingenic-JZ4780-cpuidle-driver.patch
0013-MIPS-CI20-Refresh-defconfig-to-enable-cpuidle.patch
0002-MIPS-CI20-Update-defconfig-to-support-SMP.patch
0003-MIPS-CI20-Reduce-MSC0-frequency-and-add-second-percp.patch
0004-MIPS-Ingenic-Fix-the-wrong-cpu-features.patch
0005-MIPS-kernel-Fix-the-problem-of-TLBINV-support-detect.patch
0006-MIPS-stackframe-Fix-the-problem-caused-by-the-eretnc.patch
0007-MIPS-Ingenic-Add-new-cpu-type-and-regester-macro-for.patch
0008-MIPS-hazards-Add-optimization-for-Ingenic-XBurst-CPU.patch
0009-MIPS-mm-Add-control-switch-for-Ingenic-and-Loongson-.patch

H. Nikolaus Schaller

unread,
Jan 15, 2021, 5:47:25 AM1/15/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hello,
thank you very much!

It is still a little difficult to merge with my CI20 setup (which needs to include some non-upstream patches and the HDMI stuff)
or to rebase to 5.11-rc3. One issue seems to be

commit 6ce91ba8589ab08143939f9d6a58993e36773e75
Author: Tiezhu Yang <yangt...@loongson.cn>
Date: Thu Nov 19 15:53:00 2020 +0800

MIPS: Remove cpu_has_6k_cache and cpu_has_8k_cache in cpu_cache_init()

Since commit 02cf2119684e ("Cleanup the mess in cpu_cache_init."),
cpu_has_6k_cache and cpu_has_8k_cache have no user, r6k_cache_init()
and r8k_cache_init() are not defined for over 15 years, just remove
them.

But I am trying until I get something I can test :)

BR and thanks,
Nikolaus
> <0001-MIPS-JZ4780-Introduce-SMP-support.patch><0002-MIPS-CI20-Update-defconfig-to-support-SMP.patch><0003-MIPS-CI20-Reduce-MSC0-frequency-and-add-second-percp.patch><0004-MIPS-Ingenic-Fix-the-wrong-cpu-features.patch><0005-MIPS-kernel-Fix-the-problem-of-TLBINV-support-detect.patch><0006-MIPS-stackframe-Fix-the-problem-caused-by-the-eretnc.patch><0007-MIPS-Ingenic-Add-new-cpu-type-and-regester-macro-for.patch><0008-MIPS-hazards-Add-optimization-for-Ingenic-XBurst-CPU.patch><0009-MIPS-mm-Add-control-switch-for-Ingenic-and-Loongson-.patch><0010-MIPS-mm-Add-Ingenic-XBurst-SoCs-specific-cache-drive.patch><0011-MIPS-mm-Remove-code-that-is-no-longer-needed.patch><0012-cpuidle-JZ4780-Add-Ingenic-JZ4780-cpuidle-driver.patch><0013-MIPS-CI20-Refresh-defconfig-to-enable-cpuidle.patch>

H. Nikolaus Schaller

unread,
Jan 15, 2021, 8:08:11 AM1/15/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi,

> Am 15.01.2021 um 11:47 schrieb H. Nikolaus Schaller <h...@goldelico.com>:
>
> Hello,
> thank you very much!
>
> It is still a little difficult to merge with my CI20 setup (which needs to include some non-upstream patches and the HDMI stuff)
> or to rebase to 5.11-rc3. One issue seems to be
>
> commit 6ce91ba8589ab08143939f9d6a58993e36773e75
> Author: Tiezhu Yang <yangt...@loongson.cn>
> Date: Thu Nov 19 15:53:00 2020 +0800
>
> MIPS: Remove cpu_has_6k_cache and cpu_has_8k_cache in cpu_cache_init()
>
> Since commit 02cf2119684e ("Cleanup the mess in cpu_cache_init."),
> cpu_has_6k_cache and cpu_has_8k_cache have no user, r6k_cache_init()
> and r8k_cache_init() are not defined for over 15 years, just remove
> them.
>
> But I am trying until I get something I can test :)

Ok, I have now taken v5.10.7, applied your patches and a handful of my patches (not related to Ingenic or smp or mm) and enabled SMP in my defconfig.

Well, now my CI20 gets stuck with errors like

[ 3.307785] do_page_fault(): sending SIGSEGV to udevadm for invalid read access from 00000000
[ 3.316410] epc = 00000000 in udevadm[400000+42000]
[ 3.321393] ra = 00424a88 in udevadm[400000+42000]
Segmentation fault

or on a second boot attempt a different one

[ 16.863402] do_page_fault(): sending SIGSEGV to dhclient for invalid read access from 55637f70
[ 16.872170] epc = 55613af4 in dhclient[555b0000+7f000]
[ 16.877465] ra = 555f30c8 in dhclient[555b0000+7f000]

So I think the instruction cache isn't working well enough in SMP mode?

BR and thanks,
Nikolaus

Zhou Yanjie

unread,
Jan 15, 2021, 9:29:38 AM1/15/21
to H. Nikolaus Schaller, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi Nikolaus,

On 2021/1/15 下午9:08, H. Nikolaus Schaller wrote:
> Hi,
>
This is strange, could you send me a copy of your patch? Also, which
distribution are you using? And what is the tool chain when compiling
the kernel? I use Ingenic's gcc7.2.0 tool chain, and use Debian9.

H. Nikolaus Schaller

unread,
Jan 15, 2021, 10:20:03 AM1/15/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi,
Here is the full tree:

https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/temp-5.10.7-smp

And I used this defconfig:

https://download.goldelico.com/letux-kernel/letux-5.10.7-ci20/src/DEFCONFIG

> Also, which distribution are you using?

Debian7.

> And what is the tool chain when compiling the kernel? I use Ingenic's gcc7.2.0 tool chain, and use Debian9.

It is a self-build gcc 4.9 running on MacOS for years.

All this same setup worked well with the old series of CI20 SMP patches last year.

BR,
Nikolaus

Zhou Yanjie

unread,
Jan 15, 2021, 11:00:21 AM1/15/21
to H. Nikolaus Schaller, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi Nikolaus,
Could you pack a tarball for me? My attempt to git clone always fails.
I tried your defconfig on my source code, and the compiled image can
work normally (just change the Kernel compression mode from gz to xz).

I have an additional question: Are you running in an SD card or in NAND?
My tests are all performed in the SD card.


Thanks and best regards!

H. Nikolaus Schaller

unread,
Jan 15, 2021, 1:58:58 PM1/15/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi,
I forgot to mention that we have a github mirror (it just takes some hours to arrive there but now has):

https://github.com/goldelico/letux-kernel/tree/temp-5.10.7-smp

>
>
>>
>> And I used this defconfig:
>>
>> https://download.goldelico.com/letux-kernel/letux-5.10.7-ci20/src/DEFCONFIG
>
>
> I tried your defconfig on my source code, and the compiled image can work normally (just change the Kernel compression mode from gz to xz).
>
> I have an additional question: Are you running in an SD card or in NAND? My tests are all performed in the SD card.

Yes, I also use SD card.

I think I can repeat the test tomorrow.

Best regards,
Nikolaus

H. Nikolaus Schaller

unread,
Jan 16, 2021, 1:55:34 AM1/16/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com

> Am 15.01.2021 um 16:07 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
> Or could you test the kernel image in the attachment to see if it works normally. This image is compiled on the basis of the clean kernel 5.10.7 source code with the previous 13 patches.

This one booted without segfaults with the same rootfs as before. At least I haven't seen such.

What came to my mind in the meantime is that I may be missing some entries in defconfig. AFAIR there was something with CONFIG_CPU_IDLE=y which may no (or may) be in my defconfig.

Needs more time for testing...

BR and thanks,
Nikolaus

Zhou Yanjie

unread,
Jan 16, 2021, 12:38:08 PM1/16/21
to H. Nikolaus Schaller, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
I think it may not be the problem of defconfig. I used your defconfig
with my source code to compile the image and it works normally
(temp-5.10.7-smp branch has expired before I finished downloading).

Maybe it has something to do with the tool chain version. I tried
gcc5.2.0 and gcc7.2.0, and both images work normally.

Maybe you can try the 5.2.0 version tool chain, you can find it here:
https://github.com/XBurst/CU1000-Neo


Thanks and best regards!

H. Nikolaus Schaller

unread,
Jan 16, 2021, 12:53:35 PM1/16/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com, Discussions about the Letux Kernel
Hi,

> Am 16.01.2021 um 07:55 schrieb H. Nikolaus Schaller <h...@goldelico.com>:
>
> This one booted without segfaults with the same rootfs as before. At least I haven't seen such.

I have rebuilt my tree and reinstalled and have not yet seen a segfault or hang as before.

No idea what went wrong. Could have been fetching/using the wrong defconfig. I have committed
the letux_defconfig and there is now a new branch "letux-5.10.7+jz4780-smp" [1] which appears
to work for me.

sysbench --cpu --num-threads=4 reports execution time (seconds) for some devices:

CI20 single threaded 139.4188
CI20: 69.5500
Udoo Neo (i.MX6): 287.8606 [single core Cortex A8]
RasPi 3B+: 103.3249 [dual core CI20 is faster than quad-core A53 with 1.4 GHz (in 32 bit mode)]
PocketBeagle (AM3358): 359.8562 [single core Cortex A8]
Pyra (OMAP5): 9.9983 [dual Cortex A15 with 1.5GHz]
Pinephone: 52.9954 [quad core Cortex A53 (in 32 bit mode)]

That shows that the "old" jz4780 isn't that bad in performance if we have SMP enabled.
And compared to the OMAP5 it stays quite cool (<40°C).

Next step is to try to integrate SMP with the CI20-HDMI stuff. Then we may get a first
"longterm stable kernel" SMP solution, even if the patches need some polishing for
upstreaming.

BR and thanks for all the hard work on SMP,
Nikolaus


[1] https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/letux-5.10.7%2Bjz4780-smp


Attached is some system info:

root@letux:~# cat /proc/cpuinfo
system type : JZ4780
machine : img,ci20
processor : 0
cpu model : Ingenic XBurst V4.15 FPU V0.0
BogoMIPS : 1196.85
wait instruction : yes
microsecond timers : no
tlb_entries : 32
extra interrupt vector : yes
hardware watchpoint : yes, count: 1, address/irw mask: [0x0fff]
isa : mips1 mips2 mips32r1 mips32r2
ASEs implemented :
shadow register sets : 1
kscratch registers : 0
package : 0
core : 0
VCED exceptions : not available
VCEI exceptions : not available

processor : 1
cpu model : Ingenic XBurst V4.15 FPU V0.0
BogoMIPS : 1202.58
wait instruction : yes
microsecond timers : no
tlb_entries : 32
extra interrupt vector : yes
hardware watchpoint : yes, count: 1, address/irw mask: [0x0fff]
isa : mips1 mips2 mips32r1 mips32r2
ASEs implemented :
shadow register sets : 1
kscratch registers : 0
package : 0
core : 1
VCED exceptions : not available
VCEI exceptions : not available

root@letux:~# uname -a
Linux letux 5.10.7-letux-ci20+ #4688 SMP PREEMPT Sat Jan 16 16:14:24 CET 2021 mips GNU/Linuxroot@letux:~# cat </dev/tcp/time.nist.gov/13 && sysbench --test=cpu run && cat </dev/tcp/time.nist.gov/13

59230 21-01-16 16:48:00 00 0 0 651.3 UTC(NIST) *
sysbench 0.4.12: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Doing CPU performance benchmark

Threads started!
Done.

Maximum prime number checked in CPU test: 10000


Test execution summary:
total time: 139.4414s
total number of events: 10000
total time taken by event execution: 139.4188
per-request statistics:
min: 13.90ms
avg: 13.94ms
max: 14.46ms
approx. 95 percentile: 13.98ms

Threads fairness:
events (avg/stddev): 10000.0000/0.00
execution time (avg/stddev): 139.4188/0.00


59230 21-01-16 16:50:20 00 0 0 943.6 UTC(NIST) *
root@letux:~#

H. Nikolaus Schaller

unread,
Jan 16, 2021, 12:56:22 PM1/16/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com

> Am 16.01.2021 um 18:38 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>
> I think it may not be the problem of defconfig. I used your defconfig with my source code to compile the image and it works normally (temp-5.10.7-smp branch has expired before I finished downloading).
>
> Maybe it has something to do with the tool chain version. I tried gcc5.2.0 and gcc7.2.0, and both images work normally.
>
> Maybe you can try the 5.2.0 version tool chain, you can find it here: https://github.com/XBurst/CU1000-Neo

Has turned out to be a spurious and not reproducible issue. So neither config nor toolchain.

I am now trying to integrate with our HDMI stuff (which should not be in any conflict).

> Thanks and best regards!

Same to you,
Nikolaus

dave

unread,
Jan 16, 2021, 1:05:31 PM1/16/21
to Discussions about the Letux Kernel, Zhou Yanjie, mips-creat...@googlegroups.com, Paul Boddie, Riccardo Mottola, Ezequiel Garcia
Is there a typo in the OMAP5 result? Or is it really that good :) ?

H. Nikolaus Schaller

unread,
Jan 16, 2021, 1:07:27 PM1/16/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Ok, and the SEGFAULTs are back.

So what I assume is that since I have to resolve some merge conflicts I am doing that wrongly.

This is only because we have a piling up branch letux-5.10.y which contains everything like
old SMP (disabled), HDMI and other stuff, currently up to 5.10.7.

Very likely I did test a first attempt to fix the merge conflicts instead of the clean build
on top of v5.10.7 from upstream... So I have to better revert the old SMP code first.

BR,
Nikolaus

H. Nikolaus Schaller

unread,
Jan 16, 2021, 1:10:20 PM1/16/21
to Discussions about the Letux Kernel, dave, Zhou Yanjie, Paul Boddie, mips-creat...@googlegroups.com, Riccardo Mottola, Ezequiel Garcia

> Am 16.01.2021 um 19:05 schrieb dave <da...@ds0.me>:
>
> Is there a typo in the OMAP5 result? Or is it really that good :) ?

It was copy&paste and much faster than I had expected.

Well, I am not sure if I have the same debian release on both. So if that changed...

Please verify with

cat </dev/tcp/time.nist.gov/13 && sysbench --test=cpu --num-threads=4 run && cat </dev/tcp/time.nist.gov/13

This should also allow to verify if the internal timers and calculations are done correctly.

Zhou Yanjie

unread,
Jan 17, 2021, 1:38:08 AM1/17/21
to H. Nikolaus Schaller, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Okay, waiting forward to your new progress. If possible, would you
please help to test the new cache driver (patch [10/13]). Although it is
normal in my test here, but I am worried that some possible problems
will be missed because my test coverage is not wide enough.


Thanks and best regards!


>
> BR,
> Nikolaus

H. Nikolaus Schaller

unread,
Jan 17, 2021, 11:58:54 AM1/17/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi,

> Am 17.01.2021 um 07:38 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>
>
> On 2021/1/17 上午2:07, H. Nikolaus Schaller wrote:
>>> Am 16.01.2021 um 18:56 schrieb H. Nikolaus Schaller <h...@goldelico.com>:
>>>
>>>
>>
>> Very likely I did test a first attempt to fix the merge conflicts instead of the clean build
>> on top of v5.10.7 from upstream... So I have to better revert the old SMP code first.
>
>
> Okay, waiting forward to your new progress. If possible, would you please help to test the new cache driver (patch [10/13]).

Yes, that is included and may be the reason for the problems...

> Although it is normal in my test here, but I am worried that some possible problems will be missed because my test coverage is not wide enough.

I have now found a way to cleanly apply all patches without manual conflict resolution.
Result is that it now boots with HDMI but still shows the page faults...

[ 4.422053] do_page_fault(): sending SIGSEGV to ln for invalid read access from 003f5a0c

and udevd doesn't work well so not all modules are loaded.

But the good thing is that patch [1/13]..[13/13] is now at the tip of my branch.
Therefore, I can now easily bisect between the non-SMP state which works and the SMP version.

This still does not explain why the vanilla v5.10.7 plus the SMP patches works and our tree
doesn't. Most likely we have some remains from earlier versions. The bisect should show the
location.

BTW, what I observed is that CONFIG_HOTPLUG_CPU=y is automatically removed
because

Depends on: SMP [=y] && SYS_SUPPORTS_HOTPLUG_CPU [=n]

SYS_SUPPORTS_HOTPLUG_CPU is not set for the jz4780.

I'll now start the bisect and report results asap.

BR,
Nikolaus

H. Nikolaus Schaller

unread,
Jan 17, 2021, 2:23:04 PM1/17/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Here is the result:

bb02f18302376ac8af9d0dcb03a310dc2d2c016c is the first bad commit
commit bb02f18302376ac8af9d0dcb03a310dc2d2c016c
Author: 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>
Date: Sat Dec 5 21:10:43 2020 +0800

MIPS: mm: Add Ingenic XBurst SoCs specific cache driver.

Although Ingenic's SoCs with XBurst®1 or XBurst®2 CPU cores can use
the c-r4k.c cache driver, but it does not make full use of the unique
features of Ingenic's CPU cores. To apply these feature in c-r4k.c,
largescale modifications are needed, which may adversely affect other
processors that use this driver. Therefore, a new c-ingenic.c driver
optimized for the specific features of the Ingenic CPU was created.

According to tests, the SoCs using the XBurst®1 or XBurst®2 CPU cores
can obtain varying degrees of performance improvement after using this
driver. Details are as follows:

SPEC CPU2000 UnixBench DMA Test SoC model
(int/fp) (iops/speed)
+1.7/2.9% +4.1% +2.9/4.7% JZ4775
+2.5/4.3% +14.9% +2.8/3.4% JZ4780 (SMP off)
+?.?% +21.7% +6.6/6.1% JZ4780 (SMP on)
N/A +5.1% +2.5/3.8% X1000
N/A +12.6% +3.6/5.7% X1830
N/A +2.7% +?.?/?.?% X2000 (SMT off)

Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>

arch/mips/Kconfig | 2 +-
arch/mips/include/asm/cpu-features.h | 3 +
.../asm/mach-ingenic/cpu-feature-overrides.h | 3 +-
arch/mips/ingenic/Kconfig | 4 -
arch/mips/mm/Makefile | 1 +
arch/mips/mm/c-ingenic.c | 596 +++++++++++++++++++++
arch/mips/mm/cache.c | 7 +
7 files changed, 610 insertions(+), 6 deletions(-)
create mode 100644 arch/mips/mm/c-ingenic.c

So this works on vanilla v5.10.7 but not if we add more from
letux-5.10.7. But AFAIK we have no specific patches for any of
these files. The only changes I have found are in arch/mips/ingenic/Kconfig.

So another theory is that we add some drivers which shake the
caches in a different way than without. On the other hand I had
tried the ci20_defconfig and it failed as well.

BR,
Nikolaus


Zhou Yanjie

unread,
Jan 17, 2021, 3:53:58 PM1/17/21
to H. Nikolaus Schaller, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi Nikolaus,
Could you tell me the source code you use? I think I can assist with the
test.

H. Nikolaus Schaller

unread,
Jan 17, 2021, 5:01:19 PM1/17/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi,

> Am 17.01.2021 um 21:53 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>
> Could you tell me the source code you use?

This is the tree which works. If you remove the last commit (revert) it breaks for me.
Uses letux_defconfig and has HDMI included.

https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/letux-5.10.y%2Bjz4780-smp

(or the mirror @github)

> I think I can assist with the test.
>
> Thanks and best regards!

Same to you,
Nikolaus

Zhou Yanjie

unread,
Jan 18, 2021, 4:53:46 AM1/18/21
to H. Nikolaus Schaller, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com

On 2021/1/18 上午6:01, H. Nikolaus Schaller wrote:
> Hi,
>
>> Am 17.01.2021 um 21:53 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>>
>> Could you tell me the source code you use?
> This is the tree which works. If you remove the last commit (revert) it breaks for me.
> Uses letux_defconfig and has HDMI included.
>
> https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/letux-5.10.y%2Bjz4780-smp
>
> (or the mirror @github)


Finally, I completed the code cloning. In the past few days, the network
here is a bit abnormal and access to github is very unstable. I will
start the test after a moment.

What I want to ask is, what operation has the greatest probability of
triggering SEGFAULTs? Will the kernel work normally if drop [10/13]?

H. Nikolaus Schaller

unread,
Jan 18, 2021, 5:31:44 AM1/18/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com

> Am 18.01.2021 um 10:53 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>
>
> On 2021/1/18 上午6:01, H. Nikolaus Schaller wrote:
>> Hi,
>>
>>> Am 17.01.2021 um 21:53 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>>>
>>> Could you tell me the source code you use?
>> This is the tree which works. If you remove the last commit (revert) it breaks for me.
>> Uses letux_defconfig and has HDMI included.
>>
>> https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/letux-5.10.y%2Bjz4780-smp
>>
>> (or the mirror @github)
>
>
> Finally, I completed the code cloning. In the past few days, the network here is a bit abnormal and access to github is very unstable. I will start the test after a moment.
>
> What I want to ask is, what operation has the greatest probability of triggering SEGFAULTs?

Well, it triggers segfaults, illegal instructions and kernel panics.
It appears to happen when running user-space processes because it never appears before the boot process is starting /sbin/init.
Sometimes udevd is affected (leaving a system without modules) or the error message happens in simple commands like "ln" or "cp".

But all this is anecdotal evidence rather than a real stress test...

> Will the kernel work normally if drop [10/13]?

Yes. That is what I have done as the last commit on the above mentioned branch.
I haven't really tested but by accident I had [10/13] and no SMP configured and there was also problems.
IMHO it appears to be not really SMP related but cache and the random nature and type of issues shows the same direction.

BR and thanks,
Nikolaus



Zhou Yanjie

unread,
Jan 18, 2021, 11:43:09 AM1/18/21
to H. Nikolaus Schaller, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi Nikolaus,

On 2021/1/18 下午6:31, H. Nikolaus Schaller wrote:
>> Am 18.01.2021 um 10:53 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>>
>>
>> On 2021/1/18 上午6:01, H. Nikolaus Schaller wrote:
>>> Hi,
>>>
>>>> Am 17.01.2021 um 21:53 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>>>>
>>>> Could you tell me the source code you use?
>>> This is the tree which works. If you remove the last commit (revert) it breaks for me.
>>> Uses letux_defconfig and has HDMI included.
>>>
>>> https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/letux-5.10.y%2Bjz4780-smp
>>>
>>> (or the mirror @github)
>>
>> Finally, I completed the code cloning. In the past few days, the network here is a bit abnormal and access to github is very unstable. I will start the test after a moment.
>>
>> What I want to ask is, what operation has the greatest probability of triggering SEGFAULTs?
> Well, it triggers segfaults, illegal instructions and kernel panics.
> It appears to happen when running user-space processes because it never appears before the boot process is starting /sbin/init.
> Sometimes udevd is affected (leaving a system without modules) or the error message happens in simple commands like "ln" or "cp".
>
> But all this is anecdotal evidence rather than a real stress test...


I have reproduced the error phenomenon, I did not trigger it during cp
(I used cp to copy the entire Arctic-Fox folder), only such a message
appeared in the process of cp: "sched: RT throttling activated", but it
(SEGFAULT) appeared during reboot.

And the strange thing is that in my side, HDMI still has no graphics output.

Zhou Yanjie

unread,
Jan 18, 2021, 1:24:17 PM1/18/21
to H. Nikolaus Schaller, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi Nikolaus,
Could you send me the log of your error? I may know where the problem is.

I carefully observed that when an error occurred, the printed time stamp
was abnormal (it did not advance normally, but looped in a small range).

I tracked the startup log and found that your clocksource is provided by
the TCU, and the clock frequency is 3MHz. The TCU can only count up to
16bits. At 3MHz, it will overflow about every 11ms. Frequent overflows
cause the clocksource timing disorder.

The solution is to enable the OST of JZ SoC in "Clock Source drivers" in
defconfig (notice that it is not SYSOST for X SoC), which can provide
32bits (hardware supports 64bits, but in order to compatible with older
processors, Paul's driver is provide 32bit support) maximum count range,
it can avoid the above problems.


> BR and thanks,
> Nikolaus
>
>

H. Nikolaus Schaller

unread,
Jan 18, 2021, 1:46:10 PM1/18/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi,

> Am 18.01.2021 um 19:24 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>
> Hi Nikolaus,
>
> On 2021/1/18 下午6:31, H. Nikolaus Schaller wrote:
>>> Am 18.01.2021 um 10:53 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>>>
>>>
>>> On 2021/1/18 上午6:01, H. Nikolaus Schaller wrote:
>>>> Hi,
>>>>
>>>>> Am 17.01.2021 um 21:53 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>>>>>
>>>>> Could you tell me the source code you use?
>>>> This is the tree which works. If you remove the last commit (revert) it breaks for me.
>>>> Uses letux_defconfig and has HDMI included.
>>>>
>>>> https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/letux-5.10.y%2Bjz4780-smp
>>>>
>>>> (or the mirror @github)
>>>
>>> Finally, I completed the code cloning. In the past few days, the network here is a bit abnormal and access to github is very unstable. I will start the test after a moment.
>>>
>>> What I want to ask is, what operation has the greatest probability of triggering SEGFAULTs?
>> Well, it triggers segfaults, illegal instructions and kernel panics.
>> It appears to happen when running user-space processes because it never appears before the boot process is starting /sbin/init.
>> Sometimes udevd is affected (leaving a system without modules) or the error message happens in simple commands like "ln" or "cp".
>>
>> But all this is anecdotal evidence rather than a real stress test...
>>
>>> Will the kernel work normally if drop [10/13]?
>> Yes. That is what I have done as the last commit on the above mentioned branch.
>> I haven't really tested but by accident I had [10/13] and no SMP configured and there was also problems.
>> IMHO it appears to be not really SMP related but cache and the random nature and type of issues shows the same direction.
>
>
> Could you send me the log of your error? I may know where the problem is.

Well, it is difficult to log. Sometimes boot hangs, sometimes I see a kernel panic and sometimes I get either a login: or a fallback shell. Then you can find do_page_fault() reports. I have used that as a symptom for the bisect...

>
> I carefully observed that when an error occurred, the printed time stamp was abnormal (it did not advance normally, but looped in a small range).
>
> I tracked the startup log and found that your clocksource is provided by the TCU, and the clock frequency is 3MHz. The TCU can only count up to 16bits. At 3MHz, it will overflow about every 11ms. Frequent overflows cause the clocksource timing disorder.

This is really interesting! Since we have the same effect permanently on the jz4730 (which is single core by the way). The time reported by the dmesg records is jumping back every now and then.

But: I have analysed how that works. sched_clock() reads this timer and calculates from the last known base value what the 3MHz count is. I.e. it provides 300ns precision.

The "last known basis" should be regularily updated by some high-resolution-timer which period is calculated from the OST resolution (16 bits) so that it occurs fast enough. I.e. the 16 bit timer will overflow but the base value mechanism recognises them and therefore the timer should be monotonic. But on jz4730 it isn't.

Using a 32 bit counter/timer will of course make the overflows more rare, but if they are not properly taken into account there is still a potential glitch every 12 or 23 minutes or so.

>
> The solution is to enable the OST of JZ SoC in "Clock Source drivers" in defconfig (notice that it is not SYSOST for X SoC),

> which can provide 32bits (hardware supports 64bits, but in order to compatible with older processors, Paul's driver is provide 32bit support) maximum count range, it can avoid the above problems.

Isn't it? At least on the jz4730 (built from the same tree) the OST timers are running (I had checked the past weeks).

Ah, I see. There is clocksource/ingenic-timer.c and clocksource/ingenic-ost.c

We use the ingenic-timer.c

Hm. So there seem to be two drivers for the same purpose?

BR and thanks,
Nikolaus

Zhou Yanjie

unread,
Jan 22, 2021, 8:55:41 AM1/22/21
to H. Nikolaus Schaller, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
I think a simple overflow should not cause this problem. The problem now
occurs because the overflow period is too short, and some processing
takes too long, resulting in the timing overflow more than once during
the processing, and the processing mechanism may Failure to consider the
situation of overflowing 2 or more times (or it is difficult to realize
the identification of overflowing more than 2 times), which leads to
timing disorder. I remember that Paul had several patches at the end of
2018 and early 2019 to reduce the counting frequency.


>> The solution is to enable the OST of JZ SoC in "Clock Source drivers" in defconfig (notice that it is not SYSOST for X SoC),
>> which can provide 32bits (hardware supports 64bits, but in order to compatible with older processors, Paul's driver is provide 32bit support) maximum count range, it can avoid the above problems.
> Isn't it? At least on the jz4730 (built from the same tree) the OST timers are running (I had checked the past weeks).
>
> Ah, I see. There is clocksource/ingenic-timer.c and clocksource/ingenic-ost.c
>
> We use the ingenic-timer.c
>
> Hm. So there seem to be two drivers for the same purpose?


Yes, there was only one TCU driver at first, but at the beginning of
2020 I found the timing error and gave Paul feedback, he later added the
OST driver.

I have improved the cache patch and tested it with the letux kernel. For
now, everything is normal. I will send you a new patch later.


Thanks and best regards!


>
> BR and thanks,
> Nikolaus

H. Nikolaus Schaller

unread,
Jan 22, 2021, 9:10:23 AM1/22/21
to Zhou Yanjie, Riccardo Mottola, Paul Boddie, Ezequiel Garcia, mips-creat...@googlegroups.com
Hi,

> Am 22.01.2021 um 14:55 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>
>>
>> The "last known basis" should be regularily updated by some high-resolution-timer which period is calculated from the OST resolution (16 bits) so that it occurs fast enough. I.e. the 16 bit timer will overflow but the base value mechanism recognises them and therefore the timer should be monotonic. But on jz4730 it isn't.
>>
>> Using a 32 bit counter/timer will of course make the overflows more rare, but if they are not properly taken into account there is still a potential glitch every 12 or 23 minutes or so.
>
>
> I think a simple overflow should not cause this problem. The problem now occurs because the overflow period is too short, and some processing takes too long, resulting in the timing overflow more than once during the processing, and the processing mechanism may Failure to consider the situation of overflowing 2 or more times (or it is difficult to realize the identification of overflowing more than 2 times), which leads to timing disorder. I remember that Paul had several patches at the end of 2018 and early 2019 to reduce the counting frequency.

I forgot that you had not been on our internal discussion.
We finally found that glitch.

Our implementation variant of ingenic_tcu_cevt_set_next() in the tcu driver did not set up the OST correctly for jz4730 (it differs from jz4740).

The sched_clock() uses two timers. OST0 is used for the hrtimer where events are placed in a sorted list of expiry and ingenic_tcu_cevt_set_next() is used to raise an interrupt when the next event occurs. Due to our bug the real time difference was ignores and a constant delay introduced. This made (nano)sleep to wait far to long.
One of these hrtimers is used to regularily read the OST1 and account for 16 bit overflow.
Because of the wrong behaviour of the hrtimers it did this too slow and simply did not see the overflows.

So the bug was that we did not have the hrtimers working properly. Now the jz4730 and the Skytone Alpha 400 variant I have runs quite well. Even X11 works although sluggish. The machine is almost useable and not much is missing (mainly I2C, sound and Ethernet) to start the cleanup and upstream the patches.

[1]: https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/letux-5.11-rc4%2Bjz4730

>
>
>
>>> The solution is to enable the OST of JZ SoC in "Clock Source drivers" in defconfig (notice that it is not SYSOST for X SoC),
>>> which can provide 32bits (hardware supports 64bits, but in order to compatible with older processors, Paul's driver is provide 32bit support) maximum count range, it can avoid the above problems.
>> Isn't it? At least on the jz4730 (built from the same tree) the OST timers are running (I had checked the past weeks).
>>
>> Ah, I see. There is clocksource/ingenic-timer.c and clocksource/ingenic-ost.c
>>
>> We use the ingenic-timer.c
>>
>> Hm. So there seem to be two drivers for the same purpose?
>
>
> Yes, there was only one TCU driver at first, but at the beginning of 2020 I found the timing error and gave Paul feedback, he later added the OST driver.

Ok. But it looks as if we don't need this alternative because for running the jz4730 the "old" driver suffices. As far as I see there is no other user of the special OST driver.

BTW: changing the timer to use 32 bits is not difficult (some constants in the code) and IMHO does not need to introduce a new driver.

>
> I have improved the cache patch and tested it with the letux kernel. For now, everything is normal. I will send you a new patch later.

Great! I am curious to do new tests.

Best regards,
Nikolaus

Paul Cercueil

unread,
Jan 22, 2021, 10:48:16 AM1/22/21
to MIPS Creator CI20 Development
Hi,

Le vendredi 22 janvier 2021 à 14:10:23 UTC, H. Nikolaus Schaller a écrit :
Hi,

> Am 22.01.2021 um 14:55 schrieb Zhou Yanjie
>
>>
>> The "last known basis" should be regularily updated by some high-resolution-timer which period is calculated from the OST resolution (16 bits) so that it occurs fast enough. I.e. the 16 bit timer will overflow but the base value mechanism recognises them and therefore the timer should be monotonic. But on jz4730 it isn't.
>>
>> Using a 32 bit counter/timer will of course make the overflows more rare, but if they are not properly taken into account there is still a potential glitch every 12 or 23 minutes or so.
>
>
> I think a simple overflow should not cause this problem. The problem now occurs because the overflow period is too short, and some processing takes too long, resulting in the timing overflow more than once during the processing, and the processing mechanism may Failure to consider the situation of overflowing 2 or more times (or it is difficult to realize the identification of overflowing more than 2 times), which leads to timing disorder. I remember that Paul had several patches at the end of 2018 and early 2019 to reduce the counting frequency.

I forgot that you had not been on our internal discussion.
We finally found that glitch.

Our implementation variant of ingenic_tcu_cevt_set_next() in the tcu driver did not set up the OST correctly for jz4730 (it differs from jz4740).

The sched_clock() uses two timers. OST0 is used for the hrtimer where events are placed in a sorted list of expiry and ingenic_tcu_cevt_set_next() is used to raise an interrupt when the next event occurs. Due to our bug the real time difference was ignores and a constant delay introduced. This made (nano)sleep to wait far to long.
One of these hrtimers is used to regularily read the OST1 and account for 16 bit overflow.
Because of the wrong behaviour of the hrtimers it did this too slow and simply did not see the overflows.

So the bug was that we did not have the hrtimers working properly. Now the jz4730 and the Skytone Alpha 400 variant I have runs quite well. Even X11 works although sluggish. The machine is almost useable and not much is missing (mainly I2C, sound and Ethernet) to start the cleanup and upstream the patches.

[1]: https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/letux-5.11-rc4%2Bjz4730

>
>
>
>>> The solution is to enable the OST of JZ SoC in "Clock Source drivers" in defconfig (notice that it is not SYSOST for X SoC),
>>> which can provide 32bits (hardware supports 64bits, but in order to compatible with older processors, Paul's driver is provide 32bit support) maximum count range, it can avoid the above problems.
>> Isn't it? At least on the jz4730 (built from the same tree) the OST timers are running (I had checked the past weeks).
>>
>> Ah, I see. There is clocksource/ingenic-timer.c and clocksource/ingenic-ost.c
>>
>> We use the ingenic-timer.c
>>
>> Hm. So there seem to be two drivers for the same purpose?

Two drivers for two different silicon blocks:
- ingenic-timer.c is for the standard TCU channels, which can be used either for the system timer, used as a clocksource, or as PWM;
- ingenic-ost.c which is for the OST, a specific channel decoupled from the other TCU channels, which is 64-bit, so more suited for being a OS timer.

The OST was introduced in the JZ4725B, which is newer than the JZ4740 (it's kind of a beta JZ4750), so you probably don't have it on the JZ4730. First as a 32-bit counter, then it was upgraded to 64-bit in the JZ4760B SoC.

The driver will only use it as 32-bit, not on oversight but on purpose, since the precision of the value (its number of bits) is not really important for a clocksource, but it should read as fast as possible - and reading one 32-bit word is much faster than reading two 32-bit words + making sure there's no overflow between the two reads.

Cheers,
-Paul
 
>
>
> Yes, there was only one TCU driver at first, but at the beginning of 2020 I found the timing error and gave Paul feedback, he later added the OST driver.

Ok. But it looks as if we don't need this alternative because for running the jz4730 the "old" driver suffices. As far as I see there is no other user of the special OST driver.

BTW: changing the timer to use 32 bits is not difficult (some constants in the code) and IMHO does not need to introduce a new driver.

>
> I have improved the cache patch and tested it with the letux kernel. For now, everything is normal. I will send you a new patch later.

Zhou: Could you Cc me on my crapouillou address when you do send the patches? I want to test them too :)

Cheers,
-Paul

Paul Boddie

unread,
Jan 22, 2021, 1:38:37 PM1/22/21
to H. Nikolaus Schaller, Zhou Yanjie, Riccardo Mottola, Ezequiel Garcia, mips-creat...@googlegroups.com
One reason why I stuck with the TCU driver (tcu.c), modifying it to use the
JZ4730 OST, is that the TCU driver handles multiple channels and fits in with
the existing timer mechanisms (ingenic-timer.c), even though these may have
since been extended. The ingenic-ost.c driver seems to handle only one timer
channel, although I see that ingenic-sysost.c may handle two or more channels.
Also, the OST channels on the JZ4730 seem to have the role that the TCU
channels have on the JZ4740 (which does not have an OST), and the Ingenic
kernels seem to take a similar approach.

I know it seems absurd to pretend the OST channels are TCU channels when there
is an OST driver, but it was just a question of identifying the most similar
functionality and adapting it as little as possible. This is my general
strategy with Linux drivers, even though I suspect that such adaptations are
not necessarily seen in a particularly favourable way.

Paul


Zhou Yanjie

unread,
Feb 11, 2021, 10:31:13 AM2/11/21
to mips-creat...@googlegroups.com

Hi Paul,

Sorry, I got caught up in other things last few weeks.

My original consideration was to wait for Nikolaus to complete the test before sending the patches to you. He has already helped me find several problems.

In a few days I will make a series of patches based on the kernel 5.11, and then I will send them to you.


Happy Chinese New Year!


Cheers,
-Paul
 

Great! I am curious to do new tests.

Best regards,
Nikolaus

--
You received this message because you are subscribed to the Google Groups "MIPS Creator CI20 Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mips-creator-ci2...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/mips-creator-ci20-dev/5cc49bf5-5a67-40c1-8ac0-a77cbb50e987n%40googlegroups.com.

H. Nikolaus Schaller

unread,
May 17, 2021, 4:06:04 AM5/17/21
to "周琰杰 (Zhou Yanjie)", MIPS Creator CI20 Development, Paul Boddie, Riccardo Mottola
Hi Yanjie,

did you track and update for v5.13-rc?

I think after having all the pinctrl and other fixes it could be an important addition.
I am now starting to think again about upstreaming some other CI20 additions (we have something
for the RTC and for HDMI and a fragment for ALSA).

BR,
Nikolaus


> Am 24.12.2020 um 09:38 schrieb 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>:
>
> Forward port smp support from kernel 3.18.3 of CI20_linux
> to upstream kernel 5.7.
>
> Tested-by: H. Nikolaus Schaller <h...@goldelico.com>
> Tested-by: Paul Boddie <pa...@boddie.org.uk>
> Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouy...@wanyeetech.com>
> Reviewed-by: Jiaxun Yang <jiaxu...@flygoat.com>
> ---
> arch/mips/generic/Makefile | 1 +
> arch/mips/generic/init.c | 4 +
> arch/mips/include/asm/mach-ingenic/smp.h | 88 +++++++
> arch/mips/ingenic/Kconfig | 3 +
> arch/mips/ingenic/Makefile | 11 +
> arch/mips/ingenic/smp-entry.S | 57 ++++
> arch/mips/ingenic/smp.c | 430 +++++++++++++++++++++++++++++++
> arch/mips/kernel/idle.c | 7 +-
> 8 files changed, 600 insertions(+), 1 deletion(-)
> create mode 100644 arch/mips/include/asm/mach-ingenic/smp.h
> create mode 100644 arch/mips/ingenic/Makefile
> create mode 100644 arch/mips/ingenic/smp-entry.S
> create mode 100644 arch/mips/ingenic/smp.c
>
> diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile
> index e37a59b..0e7194f 100644
> --- a/arch/mips/generic/Makefile
> +++ b/arch/mips/generic/Makefile
> @@ -7,6 +7,7 @@
> obj-y += init.o
> obj-y += irq.o
> obj-y += proc.o
> +obj-y += ../ingenic/
>
> obj-$(CONFIG_YAMON_DT_SHIM) += yamon-dt.o
> obj-$(CONFIG_LEGACY_BOARD_SEAD3) += board-sead3.o
> diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c
> index 66a1933..88e509a 100644
> --- a/arch/mips/generic/init.c
> +++ b/arch/mips/generic/init.c
> @@ -15,6 +15,7 @@
> #include <asm/fw/fw.h>
> #include <asm/irq_cpu.h>
> #include <asm/machine.h>
> +#include <asm/mach-ingenic/smp.h>
> #include <asm/mips-cps.h>
> #include <asm/prom.h>
> #include <asm/smp-ops.h>
> @@ -107,6 +108,9 @@ void __init plat_mem_setup(void)
>
> fw_init_cmdline();
> __dt_setup_arch((void *)fdt);
> +
> + if (IS_ENABLED(CONFIG_SMP))
> + jz4780_smp_init();
> }
>
> void __init device_tree_init(void)
> diff --git a/arch/mips/include/asm/mach-ingenic/smp.h b/arch/mips/include/asm/mach-ingenic/smp.h
> new file mode 100644
> index 00000000..321b647
> --- /dev/null
> +++ b/arch/mips/include/asm/mach-ingenic/smp.h
> @@ -0,0 +1,88 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2013, Paul Burton <paul....@imgtec.com>
> + * JZ4780 SMP definitions
> + */
> +
> +#ifndef __MIPS_ASM_MACH_JZ4740_SMP_H__
> +#define __MIPS_ASM_MACH_JZ4740_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 read_c0_mailbox2() __read_32bit_c0_register($20, 2)
> +#define write_c0_mailbox2(val) __write_32bit_c0_register($20, 2, val)
> +
> +#define read_c0_mailbox3() __read_32bit_c0_register($20, 3)
> +#define write_c0_mailbox3(val) __write_32bit_c0_register($20, 3, val)
> +
> +#define smp_clr_pending(mask) do { \
> + unsigned int stat; \
> + stat = read_c0_corestatus(); \
> + stat &= ~((mask) & 0xff); \
> + write_c0_corestatus(stat); \
> + } while (0)
> +
> +/*
> + * Core Control register
> + */
> +#define CORECTRL_SLEEP1M_SHIFT 17
> +#define CORECTRL_SLEEP1M (_ULCAST_(0x1) << CORECTRL_SLEEP1M_SHIFT)
> +#define CORECTRL_SLEEP0M_SHIFT 16
> +#define CORECTRL_SLEEP0M (_ULCAST_(0x1) << CORECTRL_SLEEP0M_SHIFT)
> +#define CORECTRL_RPC1_SHIFT 9
> +#define CORECTRL_RPC1 (_ULCAST_(0x1) << CORECTRL_RPC1_SHIFT)
> +#define CORECTRL_RPC0_SHIFT 8
> +#define CORECTRL_RPC0 (_ULCAST_(0x1) << CORECTRL_RPC0_SHIFT)
> +#define CORECTRL_SWRST1_SHIFT 1
> +#define CORECTRL_SWRST1 (_ULCAST_(0x1) << CORECTRL_SWRST1_SHIFT)
> +#define CORECTRL_SWRST0_SHIFT 0
> +#define CORECTRL_SWRST0 (_ULCAST_(0x1) << CORECTRL_SWRST0_SHIFT)
> +
> +/*
> + * Core Status register
> + */
> +#define CORESTATUS_SLEEP1_SHIFT 17
> +#define CORESTATUS_SLEEP1 (_ULCAST_(0x1) << CORESTATUS_SLEEP1_SHIFT)
> +#define CORESTATUS_SLEEP0_SHIFT 16
> +#define CORESTATUS_SLEEP0 (_ULCAST_(0x1) << CORESTATUS_SLEEP0_SHIFT)
> +#define CORESTATUS_IRQ1P_SHIFT 9
> +#define CORESTATUS_IRQ1P (_ULCAST_(0x1) << CORESTATUS_IRQ1P_SHIFT)
> +#define CORESTATUS_IRQ0P_SHIFT 8
> +#define CORESTATUS_IRQ0P (_ULCAST_(0x1) << CORESTATUS_IRQ8P_SHIFT)
> +#define CORESTATUS_MIRQ1P_SHIFT 1
> +#define CORESTATUS_MIRQ1P (_ULCAST_(0x1) << CORESTATUS_MIRQ1P_SHIFT)
> +#define CORESTATUS_MIRQ0P_SHIFT 0
> +#define CORESTATUS_MIRQ0P (_ULCAST_(0x1) << CORESTATUS_MIRQ0P_SHIFT)
> +
> +/*
> + * Reset Entry & IRQ Mask register
> + */
> +#define REIM_ENTRY_SHIFT 16
> +#define REIM_ENTRY (_ULCAST_(0xffff) << REIM_ENTRY_SHIFT)
> +#define REIM_IRQ1M_SHIFT 9
> +#define REIM_IRQ1M (_ULCAST_(0x1) << REIM_IRQ1M_SHIFT)
> +#define REIM_IRQ0M_SHIFT 8
> +#define REIM_IRQ0M (_ULCAST_(0x1) << REIM_IRQ0M_SHIFT)
> +#define REIM_MBOXIRQ1M_SHIFT 1
> +#define REIM_MBOXIRQ1M (_ULCAST_(0x1) << REIM_MBOXIRQ1M_SHIFT)
> +#define REIM_MBOXIRQ0M_SHIFT 0
> +#define REIM_MBOXIRQ0M (_ULCAST_(0x1) << REIM_MBOXIRQ0M_SHIFT)
> +
> +extern void jz4780_smp_init(void);
> +extern void jz4780_smp_wait_irqoff(void);
> +extern void jz4780_secondary_cpu_entry(void);
> +
> +#endif /* __MIPS_ASM_MACH_JZ4740_SMP_H__ */
> diff --git a/arch/mips/ingenic/Kconfig b/arch/mips/ingenic/Kconfig
> index 043b539..6605a0e 100644
> --- a/arch/mips/ingenic/Kconfig
> +++ b/arch/mips/ingenic/Kconfig
> @@ -8,6 +8,7 @@ config MACH_INGENIC_GENERIC
> select MACH_JZ4775
> select MACH_JZ4780
> select MACH_X1000
> + select MACH_X1830
>
> choice
> prompt "Machine type"
> @@ -69,9 +70,11 @@ config MACH_JZ4775
>
> config MACH_JZ4780
> bool
> + select GENERIC_CLOCKEVENTS_BROADCAST if SMP
> select MIPS_CPU_SCACHE
> select SYS_HAS_CPU_MIPS32_R2
> select SYS_SUPPORTS_HIGHMEM
> + select SYS_SUPPORTS_SMP
>
> config MACH_X1000
> bool
> diff --git a/arch/mips/ingenic/Makefile b/arch/mips/ingenic/Makefile
> new file mode 100644
> index 00000000..4f90eee
> --- /dev/null
> +++ b/arch/mips/ingenic/Makefile
> @@ -0,0 +1,11 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Makefile for the Ingenic JZ4740.
> +#
> +
> +# Object file lists.
> +CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
> +
> +# SMP support
> +obj-$(CONFIG_SMP) += smp.o
> +obj-$(CONFIG_SMP) += smp-entry.o
> diff --git a/arch/mips/ingenic/smp-entry.S b/arch/mips/ingenic/smp-entry.S
> new file mode 100644
> index 00000000..20049a3
> --- /dev/null
> +++ b/arch/mips/ingenic/smp-entry.S
> @@ -0,0 +1,57 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2013, Paul Burton <paul....@imgtec.com>
> + * JZ4780 SMP entry point
> + */
> +
> +#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
> +
> +.extern jz4780_cpu_entry_sp
> +.extern jz4780_cpu_entry_gp
> +
> +.section .text.smp-entry
> +.balign 0x10000
> +.set noreorder
> +LEAF(jz4780_secondary_cpu_entry)
> + mtc0 zero, CP0_CAUSE
> +
> + li t0, ST0_CU0
> + mtc0 t0, CP0_STATUS
> +
> + /* cache setup */
> + li t0, KSEG0
> + ori t1, t0, CACHE_SIZE
> + mtc0 zero, CP0_TAGLO, 0
> +1: cache Index_Store_Tag_I, 0(t0)
> + cache Index_Store_Tag_D, 0(t0)
> + bne t0, t1, 1b
> + addiu t0, t0, CACHE_LINESIZE
> +
> + /* kseg0 cache attribute */
> + mfc0 t0, CP0_CONFIG, 0
> + ori t0, t0, CONF_CM_CACHABLE_NONCOHERENT
> + mtc0 t0, CP0_CONFIG, 0
> +
> + /* pagemask */
> + mtc0 zero, CP0_PAGEMASK, 0
> +
> + /* retrieve sp */
> + la t0, jz4780_cpu_entry_sp
> + lw sp, 0(t0)
> +
> + /* retrieve gp */
> + la t0, jz4780_cpu_entry_gp
> + lw gp, 0(t0)
> +
> + /* jump to the kernel in kseg0 */
> + la t0, smp_bootstrap
> + jr t0
> + nop
> + END(jz4780_secondary_cpu_entry)
> diff --git a/arch/mips/ingenic/smp.c b/arch/mips/ingenic/smp.c
> new file mode 100644
> index 00000000..871af45
> --- /dev/null
> +++ b/arch/mips/ingenic/smp.c
> @@ -0,0 +1,430 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2013, Paul Burton <paul....@imgtec.com>
> + * JZ4780 SMP
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/of.h>
> +#include <linux/sched.h>
> +#include <linux/sched/task_stack.h>
> +#include <linux/smp.h>
> +#include <linux/tick.h>
> +#include <asm/mach-ingenic/smp.h>
> +#include <asm/r4kcache.h>
> +#include <asm/smp-ops.h>
> +
> +static struct clk *cpu_clock_gates[CONFIG_NR_CPUS] = { NULL };
> +
> +u32 jz4780_cpu_entry_sp;
> +u32 jz4780_cpu_entry_gp;
> +
> +static struct cpumask cpu_running;
> +
> +static DEFINE_SPINLOCK(smp_lock);
> +
> +#define XBURST_TAGLO_DIRTY_MASK 0xc
> +
> +static inline __always_inline notrace void wback_dcache(void)
> +{
> + unsigned long start = INDEX_BASE;
> + unsigned long end = start + current_cpu_data.dcache.waysize;
> + unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
> + unsigned long ws_end =
> + current_cpu_data.dcache.ways << current_cpu_data.dcache.waybit;
> + unsigned long ws, addr, tmp;
> +
> + /*
> + * Doing a writeback/invalidate on the whole cache has a significant
> + * performance cost. In this loop we instead only writeback/invalidate
> + * cache lines which are marked dirty. To do this we load the tag at
> + * each index and check the (Ingenic-specific) dirty bits, and only
> + * perform the operation if they are set. There is still a performance
> + * cost to this but it is nowhere near as high as blasting the whole
> + * cache.
> + */
> + for (ws = 0; ws < ws_end; ws += ws_inc) {
> + for (addr = start; addr < end; addr += cpu_dcache_line_size()) {
> + __asm__ __volatile__(
> + " .set push \n"
> + " .set noreorder \n"
> + " .set mips3 \n"
> + " cache %2, (%1) \n"
> + " ehb \n"
> + " mfc0 %0, " __stringify(CP0_TAGLO) " \n"
> + " and %0, %0, %3 \n"
> + " beq $0, %0, 1f \n"
> + " nop \n"
> + " cache %4, (%1) \n"
> + "1: .set pop \n"
> + : "=&r" (tmp)
> + : "r" (addr | ws),
> + "i" (Index_Load_Tag_D),
> + "i" (XBURST_TAGLO_DIRTY_MASK),
> + "i" (Index_Writeback_Inv_D));
> + }
> + }
> +}
> +
> +/*
> + * The Ingenic XBurst SMP variant has to write back dirty cache lines before
> + * executing wait. The CPU & cache clock will be gated until we return from
> + * the wait, and if another core attempts to access data from our data cache
> + * during this time then it will lock up.
> + */
> +void jz4780_smp_wait_irqoff(void)
> +{
> + unsigned long pending = read_c0_cause() & read_c0_status() & CAUSEF_IP;
> +
> + /*
> + * Going to idle has a significant overhead due to the cache flush so
> + * try to avoid it if we'll immediately be woken again due to an IRQ.
> + */
> + if (!need_resched() && !pending) {
> + wback_dcache();
> +
> + __asm__(
> + " .set push \n"
> + " .set mips3 \n"
> + " sync \n"
> + " wait \n"
> + " .set pop \n");
> + }
> +
> + local_irq_enable();
> +}
> +
> +static irqreturn_t mbox_handler(int irq, void *dev_id)
> +{
> + int cpu = smp_processor_id();
> + u32 action, status;
> +
> + spin_lock(&smp_lock);
> +
> + switch (cpu) {
> + case 0:
> + action = read_c0_mailbox0();
> + write_c0_mailbox0(0);
> + break;
> + case 1:
> + action = read_c0_mailbox1();
> + write_c0_mailbox1(0);
> + break;
> + case 2:
> + action = read_c0_mailbox2();
> + write_c0_mailbox2(0);
> + break;
> + case 3:
> + action = read_c0_mailbox3();
> + write_c0_mailbox3(0);
> + break;
> + default:
> + panic("unhandled cpu %d!", cpu);
> + }
> +
> + /* clear pending mailbox interrupt */
> + status = read_c0_corestatus();
> + status &= ~(CORESTATUS_MIRQ0P << cpu);
> + write_c0_corestatus(status);
> +
> + 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 jz4780_smp_setup(void)
> +{
> + struct device_node *cpu_node;
> + u32 addr, reim;
> + int cpu = 0;
> +
> + reim = read_c0_reim();
> +
> + for_each_of_cpu_node(cpu_node) {
> + __cpu_number_map[cpu] = cpu;
> + __cpu_logical_map[cpu] = cpu;
> + set_cpu_possible(cpu++, true);
> + }
> +
> + /* mask mailbox interrupts for this core */
> + reim &= ~REIM_MBOXIRQ0M;
> + write_c0_reim(reim);
> +
> + /* clear mailboxes & pending mailbox IRQs */
> + write_c0_mailbox0(0);
> + write_c0_mailbox1(0);
> + write_c0_mailbox2(0);
> + write_c0_mailbox3(0);
> + write_c0_corestatus(0);
> +
> + /* set reset entry point */
> + addr = KSEG1ADDR((u32)&jz4780_secondary_cpu_entry);
> + WARN_ON(addr & ~REIM_ENTRY);
> + reim &= ~REIM_ENTRY;
> + reim |= addr & REIM_ENTRY;
> +
> + /* unmask mailbox interrupts for this core */
> + reim |= REIM_MBOXIRQ0M;
> + write_c0_reim(reim);
> + set_c0_status(STATUSF_IP3);
> + irq_enable_hazard();
> +
> + cpumask_set_cpu(cpu, &cpu_running);
> +}
> +
> +static void jz4780_smp_prepare_cpus(unsigned int max_cpus)
> +{
> + struct device_node *cpu_node;
> + unsigned cpu, ctrl;
> + int err;
> +
> + /* setup the mailbox IRQ */
> + err = request_irq(MIPS_CPU_IRQ_BASE + 3, mbox_handler,
> + IRQF_PERCPU | IRQF_NO_THREAD, "core mailbox", NULL);
> + if (err)
> + pr_err("request_irq() on core mailbox failed\n");
> +
> + ctrl = read_c0_corectrl();
> +
> + for_each_of_cpu_node(cpu_node) {
> + cpu = of_cpu_node_to_id(cpu_node);
> + if (cpu < 0) {
> + pr_err("Failed to read index of %s\n",
> + cpu_node->full_name);
> + continue;
> + }
> +
> + /* use reset entry point from REIM register */
> + ctrl |= CORECTRL_RPC0 << cpu;
> +
> + cpu_clock_gates[cpu] = of_clk_get(cpu_node, 0);
> + if (IS_ERR(cpu_clock_gates[cpu])) {
> + cpu_clock_gates[cpu] = NULL;
> + continue;
> + }
> + }
> +
> + write_c0_corectrl(ctrl);
> +}
> +
> +static int jz4780_boot_secondary(int cpu, struct task_struct *idle)
> +{
> + unsigned long flags;
> + int err;
> + u32 ctrl;
> +
> + spin_lock_irqsave(&smp_lock, flags);
> +
> + /* ensure the core is in reset */
> + ctrl = read_c0_corectrl();
> + ctrl |= CORECTRL_SWRST0 << cpu;
> + write_c0_corectrl(ctrl);
> +
> + /* ungate core clock */
> + if (cpu_clock_gates[cpu]) {
> + err = clk_prepare(cpu_clock_gates[cpu]);
> + if (err)
> + pr_err("Failed to prepare CPU clock gate\n");
> +
> + err = clk_enable(cpu_clock_gates[cpu]);
> + if (err)
> + pr_err("Failed to ungate core clock\n");
> + }
> +
> + /* set entry sp/gp register values */
> + jz4780_cpu_entry_sp = __KSTK_TOS(idle);
> + jz4780_cpu_entry_gp = (u32)task_thread_info(idle);
> + smp_wmb();
> +
> + /* take the core out of reset */
> + ctrl &= ~(CORECTRL_SWRST0 << cpu);
> + write_c0_corectrl(ctrl);
> +
> + cpumask_set_cpu(cpu, &cpu_running);
> +
> + spin_unlock_irqrestore(&smp_lock, flags);
> +
> + return 0;
> +}
> +
> +static void jz4780_init_secondary(void)
> +{
> +}
> +
> +static void jz4780_smp_finish(void)
> +{
> + u32 reim;
> +
> + spin_lock(&smp_lock);
> +
> + /* unmask mailbox interrupts for this core */
> + reim = read_c0_reim();
> + reim |= REIM_MBOXIRQ0M << smp_processor_id();
> + write_c0_reim(reim);
> +
> + spin_unlock(&smp_lock);
> +
> + /* unmask interrupts for this core */
> + change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP2 |
> + STATUSF_IP1 | STATUSF_IP0);
> + irq_enable_hazard();
> +
> + /* force broadcast timer */
> + tick_broadcast_force();
> +}
> +
> +static void jz4780_send_ipi_single_locked(int cpu, unsigned int action)
> +{
> + u32 mbox;
> +
> + switch (cpu) {
> + case 0:
> + mbox = read_c0_mailbox0();
> + write_c0_mailbox0(mbox | action);
> + break;
> + case 1:
> + mbox = read_c0_mailbox1();
> + write_c0_mailbox1(mbox | action);
> + break;
> + case 2:
> + mbox = read_c0_mailbox2();
> + write_c0_mailbox2(mbox | action);
> + break;
> + case 3:
> + mbox = read_c0_mailbox3();
> + write_c0_mailbox3(mbox | action);
> + break;
> + default:
> + panic("unhandled cpu %d!", cpu);
> + }
> +}
> +
> +static void jz4780_send_ipi_single(int cpu, unsigned int action)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&smp_lock, flags);
> + jz4780_send_ipi_single_locked(cpu, action);
> + spin_unlock_irqrestore(&smp_lock, flags);
> +}
> +
> +static void jz4780_send_ipi_mask(const struct cpumask *mask,
> + unsigned int action)
> +{
> + unsigned long flags;
> + int cpu;
> +
> + spin_lock_irqsave(&smp_lock, flags);
> +
> + for_each_cpu(cpu, mask)
> + jz4780_send_ipi_single_locked(cpu, action);
> +
> + spin_unlock_irqrestore(&smp_lock, flags);
> +}
> +
> +#ifdef CONFIG_HOTPLUG_CPU
> +int jz4780_cpu_disable(void)
> +{
> + unsigned int cpu = smp_processor_id();
> + unsigned int status;
> +
> + local_irq_disable();
> +
> + set_cpu_online(cpu, false);
> +
> + spin_lock(&smp_lock);
> + status = read_c0_reim();
> + if (status & (1 << (cpu + 8))) {
> + status &= ~(1 << (cpu + 8));
> + status |= (1 << 8); /* irq to cpu0 */
> + write_c0_reim(status);
> + }
> +
> + spin_unlock(&smp_lock);
> +
> + return 0;
> +}
> +
> +void jz4780_cpu_die(unsigned int cpu)
> +{
> + unsigned long flags;
> + unsigned int status;
> +
> + local_irq_save(flags);
> +
> + cpumask_clear_cpu(cpu, &cpu_running);
> +
> + wmb();
> + do {
> + status = read_c0_corestatus();
> + } while (!(status & (1 << (cpu + 16))));
> +
> + clk_disable_unprepare(cpu_clock_gates[cpu]);
> +
> + local_irq_restore(flags);
> +}
> +
> +void __play_dead(void)
> +{
> + __asm__ __volatile__ (
> + " .set push \n"
> + " .set mips3 \n"
> + " sync \n"
> + " wait \n"
> + " .set pop \n");
> +}
> +
> +void play_dead(void) {
> + void (*do_play_dead)(void) = (void (*)(void)) KSEG1ADDR(__play_dead);
> + unsigned int cpu = smp_processor_id();
> +
> +
> + local_irq_disable();
> +
> + switch (cpu) {
> + case 0:
> + write_c0_mailbox0(0);
> + break;
> + case 1:
> + write_c0_mailbox1(0);
> + break;
> + }
> +
> + smp_clr_pending(1 << cpu);
> +
> + while(1) {
> + while(cpumask_test_cpu(cpu, &cpu_running))
> + ;
> + blast_icache32();
> + blast_dcache32();
> +
> + do_play_dead();
> + }
> +}
> +#endif
> +
> +static struct plat_smp_ops jz4780_smp_ops = {
> + .send_ipi_single = jz4780_send_ipi_single,
> + .send_ipi_mask = jz4780_send_ipi_mask,
> + .init_secondary = jz4780_init_secondary,
> + .smp_finish = jz4780_smp_finish,
> + .boot_secondary = jz4780_boot_secondary,
> + .smp_setup = jz4780_smp_setup,
> + .prepare_cpus = jz4780_smp_prepare_cpus,
> +#ifdef CONFIG_HOTPLUG_CPU
> + .cpu_disable = jz4780_cpu_disable,
> + .cpu_die = jz4780_cpu_die,
> +#endif
> +};
> +
> +void __init jz4780_smp_init(void)
> +{
> + register_smp_ops(&jz4780_smp_ops);
> +}
> diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c
> index 18e69eb..1aa2192 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/mach-ingenic/smp.h>
>
> /*
> * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
> @@ -172,7 +173,6 @@ void __init check_wait(void)
> case CPU_CAVIUM_OCTEON_PLUS:
> case CPU_CAVIUM_OCTEON2:
> case CPU_CAVIUM_OCTEON3:
> - case CPU_XBURST:
> case CPU_LOONGSON32:
> case CPU_XLR:
> case CPU_XLP:
> @@ -247,6 +247,11 @@ void __init check_wait(void)
> cpu_wait = r4k_wait;
> */
> break;
> + case CPU_XBURST:
> + if (IS_ENABLED(CONFIG_SMP))
> + cpu_wait = jz4780_smp_wait_irqoff;
> + else
> + cpu_wait = r4k_wait;
> default:
> break;
> }
> --
> 2.7.4
>

H. Nikolaus Schaller

unread,
May 17, 2021, 4:44:35 AM5/17/21
to "周琰杰 (Zhou Yanjie)", Paul Boddie, MIPS Creator CI20 Development, Riccardo Mottola
Hi,
anyone worked on cpufreq support for jz4780 (and maybe other Ingenic SoC)?

https://elinux.org/CI20_upstream says:

4770 has [1], but clock infrastructure is different. Ingenic kernel had [2] for 4780. Not ported to 3.16 yet.

[1] https://github.com/gcwnow/linux/commit/58cf5778deb2b72e45cca6b670d8b25809ecdc82
[2] https://github.com/ZubairLK/CI20_linux/blob/75f15b9f845416b349268dc62d1274be11455c13/arch/mips/xburst/soc-4775/common/cpufreq.c

BR and thanks,
Nikolaus

Zhou Yanjie

unread,
May 18, 2021, 4:56:38 AM5/18/21
to H. Nikolaus Schaller, MIPS Creator CI20 Development, Paul Boddie, Riccardo Mottola
Hi Nikolaus,


On 2021/5/17 下午4:05, H. Nikolaus Schaller wrote:
> Hi Yanjie,
>
> did you track and update for v5.13-rc?
>
> I think after having all the pinctrl and other fixes it could be an important addition.
> I am now starting to think again about upstreaming some other CI20 additions (we have something
> for the RTC and for HDMI and a fragment for ALSA).


I just finished a new SMP driver last week, which supported both the old
XBurst1 (JZ4780) and new XBurst2 (X2000, X2100, X2500), but because
XBurst2 are greatly different from XBurst1, so the code change involved
a lot of place (IRQ and clocksource), I expect that the preview version
can be out in about two days (based on 5.12, code quality may be not so
good), I look forward to your testing and proposing advice.


BTW, do you have free time to help port the X1830 drm driver? The
Ingenic SDK source code here is febdev, but on the mainline Ingenic SoCs
have been switched from fbdev to drm long ago, and unfortunately, I
don't know drm at all, so I don't know what should I do.


Thanks and best regards!

H. Nikolaus Schaller

unread,
May 19, 2021, 10:17:27 AM5/19/21
to Zhou Yanjie, MIPS Creator CI20 Development, Paul Boddie, Riccardo Mottola
Hi,

> Am 18.05.2021 um 10:54 schrieb Zhou Yanjie <zhouy...@wanyeetech.com>:
>
> Hi Nikolaus,
>
>
> On 2021/5/17 下午4:05, H. Nikolaus Schaller wrote:
>> Hi Yanjie,
>>
>> did you track and update for v5.13-rc?
>>
>> I think after having all the pinctrl and other fixes it could be an important addition.
>> I am now starting to think again about upstreaming some other CI20 additions (we have something
>> for the RTC and for HDMI and a fragment for ALSA).
>
>
> I just finished a new SMP driver last week, which supported both the old XBurst1 (JZ4780) and new XBurst2 (X2000, X2100, X2500), but because XBurst2 are greatly different from XBurst1, so the code change involved a lot of place (IRQ and clocksource), I expect that the preview version can be out in about two days (based on 5.12, code quality may be not so good), I look forward to your testing and proposing advice.

Fine. Will be happy to test.

> BTW, do you have free time to help port the X1830 drm driver? The Ingenic SDK source code here is febdev, but on the mainline Ingenic SoCs have been switched from fbdev to drm long ago, and unfortunately, I don't know drm at all, so I don't know what should I do.

Hm. What is "free time"? Unfortunately I am doing all these things more and more as a hobby and I should focus more one on thing to get it done :)

But I can of course give advice.

Generally it depends on the LCD controller. If it is similar enough to an existing one like jz4760 or jz4780 then it might only need some adjustments of the existing driver. The same happened for the jz4730 driver which just has some tweaks compared to jz4740:

https://git.goldelico.com/?p=letux-kernel.git;a=blobdiff;f=drivers/gpu/drm/ingenic/ingenic-drm-drv.c;h=65815573b05003383abdd01335b371f9bbb3d847;hp=0bca9780f021710c740aa0bd2d6dc2e81766daf7;hb=21ea080994114049888109236bf12699367b55d2;hpb=206af5f1ddebd28fb79d674c8c3deff981504ed7

Plus some device tree entries.

Thanks as well and best regards,
Nikolaus
> --
> You received this message because you are subscribed to the Google Groups "MIPS Creator CI20 Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to mips-creator-ci2...@googlegroups.com.
> To view this discussion on the web, visit https://groups.google.com/d/msgid/mips-creator-ci20-dev/f3bc3f33-0b87-494e-84c7-f584059b0e49%40wanyeetech.com.

Reply all
Reply to author
Forward
0 new messages