enable Hisilicon HiP04 SoC
Subsystems (17)
v3 cover enable Hisilicon HiP04 SoC
Changelog:
v3:
* Replace CONFIG_ARCH_MULTI_V7 by CONFIG_ARCH_MULTI_V7_LPAE in some SoC.
* Update MCPM code based on Dave's patch.
* Remove MCPM node in DTS file. Use sysctrl & fabric node instead.
* Move hardcoding on bootwrapper into DTS file.
* Append the CONFIG_MCPM_QUAD_CLUSTER for HiP04.
* Fix the return value from gic_get_cpumask() if it's used in standard gic.
* Add the vgic support on HiP04 GIC.
* Add virtualization support in HiP04 defconfig.
v2:
* Append ARCH_MULTI_V7_LPAE configuration. Define ARCH_MULTI_V7 to only support non-LPAE platform.
* Append document of DT supporting.
* Append ARCH_HISI in hi3xxx_defconfig.
* Enable errata 798181 for HiP04 SoC.
* Add PMU support.
Haojian Zhuang (11):
ARM: debug: add HiP04 debug uart
ARM: append ARCH_MULTI_V7_LPAE
ARM: hisi: add ARCH_HISI
irq: gic: use mask field in GICC_IAR
irq: gic: support hip04 gic
ARM: mcpm: support 4 clusters in HiP04
ARM: hisi: add hip04 SoC support
ARM: dts: add hip04-d01 dts file
ARM: config: append hip04_defconfig
ARM: config: select ARCH_HISI in hi3xxx_defconfig
virt: arm: support hip04 gic
Kefeng Wang (2):
ARM: hisi: enable erratum 798181 of A15 on HiP04
ARM: dts: Add PMU support in HiP04
Documentation/devicetree/bindings/arm/gic.txt | 1 + .../bindings/arm/hisilicon/hisilicon.txt | 10 + .../devicetree/bindings/clock/hip04-clock.txt | 20 ++ arch/arm/Kconfig | 19 +- arch/arm/Kconfig.debug | 10 + arch/arm/Makefile | 2 +- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/hip04-d01.dts | 74 +++++ arch/arm/boot/dts/hip04.dtsi | 259 ++++++++++++++++ arch/arm/configs/hi3xxx_defconfig | 1 + arch/arm/configs/hip04_defconfig | 74 +++++ arch/arm/include/asm/mcpm.h | 5 + arch/arm/kvm/interrupts_head.S | 23 +- arch/arm/mach-berlin/Kconfig | 2 +- arch/arm/mach-highbank/Kconfig | 2 +- arch/arm/mach-hisi/Kconfig | 26 +- arch/arm/mach-hisi/Makefile | 1 + arch/arm/mach-hisi/core.h | 2 + arch/arm/mach-hisi/hisilicon.c | 12 + arch/arm/mach-hisi/platmcpm.c | 334 +++++++++++++++++++++ arch/arm/mach-mvebu/Kconfig | 6 +- arch/arm/mach-omap2/Kconfig | 4 +- arch/arm/mach-qcom/Kconfig | 2 +- arch/arm/mach-shmobile/Kconfig | 2 +- arch/arm/mach-tegra/Kconfig | 2 +- arch/arm/mach-vexpress/Kconfig | 2 +- drivers/irqchip/irq-gic.c | 155 +++++++--- include/linux/irqchip/arm-gic.h | 5 + virt/kvm/arm/vgic.c | 10 +- 29 files changed, 998 insertions(+), 68 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/hip04-clock.txt create mode 100644 arch/arm/boot/dts/hip04-d01.dts create mode 100644 arch/arm/boot/dts/hip04.dtsi create mode 100644 arch/arm/configs/hip04_defconfig create mode 100644 arch/arm/mach-hisi/platmcpm.c
Signature · 1 line
1.8.3.2
PATCH v3 1/13 ARM: debug: add HiP04 debug uart
Add the support of Hisilicon HiP04 debug uart.
--- arch/arm/Kconfig.debug | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/arm/Kconfig.debug +10 -0
@@ -223,6 +223,14 @@ choice Say Y here if you want kernel low-level debugging support on HI3716 UART. + config DEBUG_HIP04_UART + bool "Hisilicon HiP04 Debug UART" + depends on ARCH_HIP04 + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + on HIP04 UART. + config DEBUG_HIGHBANK_UART bool "Kernel low-level debugging messages via Highbank UART" depends on ARCH_HIGHBANK
@@ -1044,6 +1052,7 @@ config DEBUG_UART_PHYS default 0xd4017000 if DEBUG_MMP_UART2 default 0xd4018000 if DEBUG_MMP_UART3 default 0xe0000000 if ARCH_SPEAR13XX + default 0xe4007000 if DEBUG_HIP04_UART default 0xf0000be0 if ARCH_EBSA110 default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE default 0xf1012000 if ARCH_DOVE || ARCH_KIRKWOOD || ARCH_MV78XX0 || \
@@ -1076,6 +1085,7 @@ config DEBUG_UART_VIRT default 0xf4090000 if ARCH_LPC32XX default 0xf4200000 if ARCH_GEMINI default 0xf7fc9000 if DEBUG_BERLIN_UART + default 0xf8007000 if DEBUG_HIP04_UART default 0xf8009000 if DEBUG_VEXPRESS_UART0_CA9 default 0xf8090000 if DEBUG_VEXPRESS_UART0_RS1 default 0xfb009000 if DEBUG_REALVIEW_STD_PORT
Signature · 1 line
1.8.3.2
PATCH v3 2/13 ARM: append ARCH_MULTI_V7_LPAE
In reply to Haojian ZhuangAdd new ARCH_MULTI_V7_LPAE config. It will select ARM_LPAE only both ARCH_MULTI_V6 & ARCH_MULTI_V7 is disabled.
ARCH_MULTI_V7 means non-LPAE platform.
--- arch/arm/Kconfig | 9 ++++++++- arch/arm/mach-berlin/Kconfig | 2 +- arch/arm/mach-highbank/Kconfig | 2 +- arch/arm/mach-mvebu/Kconfig | 6 +++--- arch/arm/mach-omap2/Kconfig | 4 ++-- arch/arm/mach-qcom/Kconfig | 2 +- arch/arm/mach-shmobile/Kconfig | 2 +- arch/arm/mach-tegra/Kconfig | 2 +- arch/arm/mach-vexpress/Kconfig | 2 +- 9 files changed, 19 insertions(+), 12 deletions(-)
arch/arm/Kconfig +8 -1
@@ -918,12 +918,19 @@ config ARCH_MULTI_V6 select CPU_V6K config ARCH_MULTI_V7 - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)" + bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)" default y select ARCH_MULTI_V6_V7 select CPU_V7 select HAVE_SMP +config ARCH_MULTI_V7_LPAE + bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)" + select ARCH_MULTI_V6_V7 + select CPU_V7 + select HAVE_SMP + select ARM_LPAE if !(ARCH_MULTI_V6 || ARCH_MULTI_V7) + config ARCH_MULTI_V6_V7 bool select MIGHT_HAVE_CACHE_L2X0
arch/arm/mach-berlin/Kconfig +1 -1
@@ -1,5 +1,5 @@ config ARCH_BERLIN - bool "Marvell Berlin SoCs" if ARCH_MULTI_V7 + bool "Marvell Berlin SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE) select ARM_GIC select GENERIC_IRQ_CHIP select DW_APB_ICTL
arch/arm/mach-highbank/Kconfig +1 -1
@@ -1,5 +1,5 @@ config ARCH_HIGHBANK - bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7 + bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7_LPAE select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE select ARCH_HAS_CPUFREQ select ARCH_HAS_HOLES_MEMORYMODEL
arch/arm/mach-mvebu/Kconfig +3 -3
@@ -1,5 +1,5 @@ config ARCH_MVEBU - bool "Marvell Engineering Business Unit (MVEBU) SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V5) + bool "Marvell Engineering Business Unit (MVEBU) SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE || ARCH_MULTI_V5) select ARCH_SUPPORTS_BIG_ENDIAN select CLKSRC_MMIO select GENERIC_IRQ_CHIP
@@ -23,7 +23,7 @@ config MACH_MVEBU_V7 select CACHE_L2X0 config MACH_ARMADA_370 - bool "Marvell Armada 370 boards" if ARCH_MULTI_V7 + bool "Marvell Armada 370 boards" if ARCH_MULTI_V7_LPAE select ARMADA_370_CLK select CPU_PJ4B select MACH_MVEBU_V7
@@ -59,7 +59,7 @@ config MACH_ARMADA_38X on the Marvell Armada 380/385 SoC with device tree. config MACH_ARMADA_XP - bool "Marvell Armada XP boards" if ARCH_MULTI_V7 + bool "Marvell Armada XP boards" if ARCH_MULTI_V7_LPAE select ARMADA_XP_CLK select CPU_PJ4B select MACH_MVEBU_V7
arch/arm/mach-omap2/Kconfig +2 -2
@@ -41,7 +41,7 @@ config ARCH_OMAP4 config SOC_OMAP5 bool "TI OMAP5" - depends on ARCH_MULTI_V7 + depends on ARCH_MULTI_V7_LPAE select ARCH_OMAP2PLUS select ARCH_HAS_OPP select ARM_CPU_SUSPEND if PM
@@ -68,7 +68,7 @@ config SOC_AM43XX config SOC_DRA7XX bool "TI DRA7XX" - depends on ARCH_MULTI_V7 + depends on ARCH_MULTI_V7_LPAE select ARCH_OMAP2PLUS select ARCH_HAS_OPP select ARM_CPU_SUSPEND if PM
arch/arm/mach-qcom/Kconfig +1 -1
@@ -1,5 +1,5 @@ config ARCH_QCOM - bool "Qualcomm Support" if ARCH_MULTI_V7 + bool "Qualcomm Support" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE) select ARCH_REQUIRE_GPIOLIB select ARM_GIC select CLKSRC_OF
arch/arm/mach-shmobile/Kconfig +1 -1
@@ -2,7 +2,7 @@ config ARCH_SHMOBILE bool config ARCH_SHMOBILE_MULTI - bool "Renesas ARM SoCs" if ARCH_MULTI_V7 + bool "Renesas ARM SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE) depends on MMU select ARCH_SHMOBILE select HAVE_ARM_SCU if SMP
arch/arm/mach-tegra/Kconfig +1 -1
@@ -1,5 +1,5 @@ config ARCH_TEGRA - bool "NVIDIA Tegra" if ARCH_MULTI_V7 + bool "NVIDIA Tegra" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE) select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
arch/arm/mach-vexpress/Kconfig +1 -1
@@ -1,5 +1,5 @@ config ARCH_VEXPRESS - bool "ARM Ltd. Versatile Express family" if ARCH_MULTI_V7 + bool "ARM Ltd. Versatile Express family" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE) select ARCH_REQUIRE_GPIOLIB select ARCH_SUPPORTS_BIG_ENDIAN select ARM_AMBA
Signature · 1 line
1.8.3.2
PATCH v3 2/13 ARM: append ARCH_MULTI_V7_LPAE
Hi Haojian,
Quoted 23 lines · Haojian Zhuang
Add new
ARCH_MULTI_V7_LPAEconfig. It will selectARM_LPAEonly bothARCH_MULTI_V6&ARCH_MULTI_V7is disabled.
ARCH_MULTI_V7means non-LPAE platform.Signed-off-by Haojian Zhuang <[email protected]>--- arch/arm/Kconfig | 9 ++++++++- arch/arm/mach-berlin/Kconfig | 2 +- arch/arm/mach-highbank/Kconfig | 2 +- arch/arm/mach-mvebu/Kconfig | 6 +++--- arch/arm/mach-omap2/Kconfig | 4 ++-- arch/arm/mach-qcom/Kconfig | 2 +- arch/arm/mach-shmobile/Kconfig | 2 +- arch/arm/mach-tegra/Kconfig | 2 +- arch/arm/mach-vexpress/Kconfig | 2 +- 9 files changed, 19 insertions(+), 12 deletions(-)arch/arm/Kconfig +0
-0
arch/arm/Kconfig config ARCH_MULTI_V6 · line 921
Quoted 5 lines
arch/arm/Kconfig +1
-1@@ -918,12 +918,19 @@ config ARCH_MULTI_V6 select CPU_V6K config ARCH_MULTI_V7 - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)" + bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)"
Actually some PJ4B are also non LPAE capable
arch/arm/Kconfig config ARCH_MULTI_V6 · line 928
Quoted 7 lines
arch/arm/Kconfig +2
-0default y select ARCH_MULTI_V6_V7 select CPU_V7 select HAVE_SMP +config ARCH_MULTI_V7_LPAE + bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)"
Only Armada XP is LPAE capable, and and the CPU is not a "simple" PJ4B but a PJ4B-MP
Quoted 42 lines
arch/arm/Kconfig +5
-0+ select ARCH_MULTI_V6_V7 + select CPU_V7 + select HAVE_SMP + select ARM_LPAE if !(ARCH_MULTI_V6 || ARCH_MULTI_V7) + config ARCH_MULTI_V6_V7 bool select MIGHT_HAVE_CACHE_L2X0arch/arm/mach-berlin/Kconfig +1
-1@@ -1,5 +1,5 @@ config ARCH_BERLIN - bool "Marvell Berlin SoCs" if ARCH_MULTI_V7 + bool "Marvell Berlin SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE) select ARM_GIC select GENERIC_IRQ_CHIP select DW_APB_ICTLarch/arm/mach-highbank/Kconfig +1
-1@@ -1,5 +1,5 @@ config ARCH_HIGHBANK - bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7 + bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7_LPAE select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE select ARCH_HAS_CPUFREQ select ARCH_HAS_HOLES_MEMORYMODELarch/arm/mach-mvebu/Kconfig +1
-1@@ -1,5 +1,5 @@ config ARCH_MVEBU - bool "Marvell Engineering Business Unit (MVEBU) SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V5) + bool "Marvell Engineering Business Unit (MVEBU) SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V7_LPAE || ARCH_MULTI_V5) select ARCH_SUPPORTS_BIG_ENDIAN select CLKSRC_MMIO select GENERIC_IRQ_CHIP
arch/arm/mach-mvebu/Kconfig config MACH_MVEBU_V7 · line 26
Quoted 5 lines
arch/arm/mach-mvebu/Kconfig +1
-1@@ -23,7 +23,7 @@ config MACH_MVEBU_V7 select CACHE_L2X0 config MACH_ARMADA_370 - bool "Marvell Armada 370 boards" if ARCH_MULTI_V7 + bool "Marvell Armada 370 boards" if ARCH_MULTI_V7_LPAE
Armada 370 is not LPAE capable
arch/arm/mach-mvebu/Kconfig config MACH_ARMADA_38X · line 65
Quoted 12 lines
arch/arm/mach-mvebu/Kconfig +1
-1select ARMADA_370_CLK select CPU_PJ4B select MACH_MVEBU_V7@@ -59,7 +59,7 @@ config MACH_ARMADA_38X on the Marvell Armada 380/385 SoC with device tree. config MACH_ARMADA_XP - bool "Marvell Armada XP boards" if ARCH_MULTI_V7 + bool "Marvell Armada XP boards" if ARCH_MULTI_V7_LPAE select ARMADA_XP_CLK select CPU_PJ4B select MACH_MVEBU_V7
Thanks,
Gregory
Signature · 4 lines
Gregory Clement, Free Electrons Kernel, drivers, real-time and embedded Linux development, consulting, training and support. http://free-electrons.com
PATCH v3 2/13 ARM: append ARCH_MULTI_V7_LPAE
Quoted 39 lines · Gregory CLEMENT
Hi Haojian,
Quoted 23 lines · Haojian Zhuang
Add new
ARCH_MULTI_V7_LPAEconfig. It will selectARM_LPAEonly bothARCH_MULTI_V6&ARCH_MULTI_V7is disabled.
ARCH_MULTI_V7means non-LPAE platform.Signed-off-by Haojian Zhuang <[email protected]>--- arch/arm/Kconfig | 9 ++++++++- arch/arm/mach-berlin/Kconfig | 2 +- arch/arm/mach-highbank/Kconfig | 2 +- arch/arm/mach-mvebu/Kconfig | 6 +++--- arch/arm/mach-omap2/Kconfig | 4 ++-- arch/arm/mach-qcom/Kconfig | 2 +- arch/arm/mach-shmobile/Kconfig | 2 +- arch/arm/mach-tegra/Kconfig | 2 +- arch/arm/mach-vexpress/Kconfig | 2 +- 9 files changed, 19 insertions(+), 12 deletions(-)arch/arm/Kconfig +0
-0arch/arm/Kconfig config ARCH_MULTI_V6 · line 921
Quoted 5 lines
arch/arm/Kconfig +1
-1@@ -918,12 +918,19 @@ config ARCH_MULTI_V6 select CPU_V6K config ARCH_MULTI_V7 - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)" + bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)"Actually some PJ4B are also non LPAE capable
Quoted 5 lines
arch/arm/Kconfig +0
-0default y select ARCH_MULTI_V6_V7 select CPU_V7 select HAVE_SMP
Quoted 4 lines
arch/arm/Kconfig config ARCH_MULTI_V6 · line 928
Quoted 2 lines
arch/arm/Kconfig +2
-0+config ARCH_MULTI_V7_LPAE + bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)"Only Armada XP is LPAE capable, and and the CPU is not a "simple" PJ4B but a PJ4B-MP
Do you mind that I append CPU_PJ4B_MP?
Quoted 30 lines
arch/arm/Kconfig config ARCH_MULTI_V6 · line 930
Quoted 4 lines
arch/arm/Kconfig +1
-1config MACH_ARMADA_370 - bool "Marvell Armada 370 boards" if ARCH_MULTI_V7 + bool "Marvell Armada 370 boards" if ARCH_MULTI_V7_LPAEArmada 370 is not LPAE capable
arch/arm/Kconfig config MACH_ARMADA_38X · line 65
Quoted 12 lines
arch/arm/Kconfig +1
-1select ARMADA_370_CLK select CPU_PJ4B select MACH_MVEBU_V7@@ -59,7 +59,7 @@ config MACH_ARMADA_38X on the Marvell Armada 380/385 SoC with device tree. config MACH_ARMADA_XP - bool "Marvell Armada XP boards" if ARCH_MULTI_V7 + bool "Marvell Armada XP boards" if ARCH_MULTI_V7_LPAE select ARMADA_XP_CLK select CPU_PJ4B select MACH_MVEBU_V7Thanks,
Gregory
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
PATCH v3 2/13 ARM: append ARCH_MULTI_V7_LPAE
Quoted 41 lines · Haojian Zhuang
Quoted 39 lines · Gregory CLEMENT
Hi Haojian,
Quoted 23 lines · Haojian Zhuang
Add new
ARCH_MULTI_V7_LPAEconfig. It will selectARM_LPAEonly bothARCH_MULTI_V6&ARCH_MULTI_V7is disabled.
ARCH_MULTI_V7means non-LPAE platform.Signed-off-by Haojian Zhuang <[email protected]>--- arch/arm/Kconfig | 9 ++++++++- arch/arm/mach-berlin/Kconfig | 2 +- arch/arm/mach-highbank/Kconfig | 2 +- arch/arm/mach-mvebu/Kconfig | 6 +++--- arch/arm/mach-omap2/Kconfig | 4 ++-- arch/arm/mach-qcom/Kconfig | 2 +- arch/arm/mach-shmobile/Kconfig | 2 +- arch/arm/mach-tegra/Kconfig | 2 +- arch/arm/mach-vexpress/Kconfig | 2 +- 9 files changed, 19 insertions(+), 12 deletions(-)arch/arm/Kconfig +0
-0arch/arm/Kconfig config ARCH_MULTI_V6 · line 921
Quoted 5 lines
arch/arm/Kconfig +1
-1@@ -918,12 +918,19 @@ config ARCH_MULTI_V6 select CPU_V6K config ARCH_MULTI_V7 - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)" + bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)"Actually some PJ4B are also non LPAE capable
Quoted 5 lines
arch/arm/Kconfig +0
-0default y select ARCH_MULTI_V6_V7 select CPU_V7 select HAVE_SMP
Quoted 6 lines
Quoted 4 lines
arch/arm/Kconfig config ARCH_MULTI_V6 · line 928
Quoted 2 lines
arch/arm/Kconfig +2
-0+config ARCH_MULTI_V7_LPAE + bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)"Only Armada XP is LPAE capable, and and the CPU is not a "simple" PJ4B but a PJ4B-MP
Do you mind that I append
CPU_PJ4B_MP?
Currently we make no difference in the code between PJ4B and PJ4B-MP. Moreover the ARCH_MULTI_V7_LPAE vs ARCH_MULTI_V7 si done by SoC not by CPU.
Maybe I missed something, what is your proposal?
Quoted 31 lines
Quoted 31 lines
arch/arm/Kconfig config ARCH_MULTI_V6 · line 930
Quoted 5 lines
arch/arm/Kconfig +1
-1config MACH_ARMADA_370 - bool "Marvell Armada 370 boards" if ARCH_MULTI_V7 + bool "Marvell Armada 370 boards" if ARCH_MULTI_V7_LPAEArmada 370 is not LPAE capable
arch/arm/Kconfig config MACH_ARMADA_38X · line 65
Quoted 12 lines
arch/arm/Kconfig +1
-1select ARMADA_370_CLK select CPU_PJ4B select MACH_MVEBU_V7@@ -59,7 +59,7 @@ config MACH_ARMADA_38X on the Marvell Armada 380/385 SoC with device tree. config MACH_ARMADA_XP - bool "Marvell Armada XP boards" if ARCH_MULTI_V7 + bool "Marvell Armada XP boards" if ARCH_MULTI_V7_LPAE select ARMADA_XP_CLK select CPU_PJ4B select MACH_MVEBU_V7Thanks,
Gregory
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
Signature · 4 lines
Gregory Clement, Free Electrons Kernel, drivers, real-time and embedded Linux development, consulting, training and support. http://free-electrons.com
PATCH v3 2/13 ARM: append ARCH_MULTI_V7_LPAE
Quoted 47 lines · Gregory CLEMENT
Quoted 46 lines · Haojian Zhuang
Quoted 43 lines · Gregory CLEMENT
Hi Haojian,
Quoted 23 lines · Haojian Zhuang
Add new
ARCH_MULTI_V7_LPAEconfig. It will selectARM_LPAEonly bothARCH_MULTI_V6&ARCH_MULTI_V7is disabled.
ARCH_MULTI_V7means non-LPAE platform.Signed-off-by Haojian Zhuang <[email protected]>--- arch/arm/Kconfig | 9 ++++++++- arch/arm/mach-berlin/Kconfig | 2 +- arch/arm/mach-highbank/Kconfig | 2 +- arch/arm/mach-mvebu/Kconfig | 6 +++--- arch/arm/mach-omap2/Kconfig | 4 ++-- arch/arm/mach-qcom/Kconfig | 2 +- arch/arm/mach-shmobile/Kconfig | 2 +- arch/arm/mach-tegra/Kconfig | 2 +- arch/arm/mach-vexpress/Kconfig | 2 +- 9 files changed, 19 insertions(+), 12 deletions(-)arch/arm/Kconfig +0
-0arch/arm/Kconfig config ARCH_MULTI_V6 · line 921
Quoted 5 lines
arch/arm/Kconfig +1
-1@@ -918,12 +918,19 @@ config ARCH_MULTI_V6 select CPU_V6K config ARCH_MULTI_V7 - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)" + bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)"Actually some PJ4B are also non LPAE capable
arch/arm/Kconfig config ARCH_MULTI_V6 · line 928
Quoted 7 lines
arch/arm/Kconfig +2
-0default y select ARCH_MULTI_V6_V7 select CPU_V7 select HAVE_SMP +config ARCH_MULTI_V7_LPAE + bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)"Only Armada XP is LPAE capable, and and the CPU is not a "simple" PJ4B but a PJ4B-MP
Quoted 8 lines
Quoted 1 line
Do you mind that I append
CPU_PJ4B_MP?Currently we make no difference in the code between PJ4B and PJ4B-MP. Moreover the
ARCH_MULTI_V7_LPAEvsARCH_MULTI_V7si done by SoC not by CPU.Maybe I missed something, what is your proposal?
Since they're same between PJ4B & PJ4B-MP, I shouldn't append a new PJ4B_MP.
I'll only use both ARCH_MULTI_V7 & ARCH_MULTI_V7_LPAE as the precondition on ARMADA_XP. I'll keep ARCH_MULTI_V7 as the precondition on other armada chips in mach-berlin directory.
So when multi_v7_lpae_defconfig is appended, only ARMADA_XP is built from mach-berlin directory. Is it OK?
Regards
Haojian
PATCH v3 2/13 ARM: append ARCH_MULTI_V7_LPAE
Quoted 55 lines · Haojian Zhuang
Quoted 53 lines · Gregory CLEMENT
Quoted 41 lines · Haojian Zhuang
Quoted 39 lines · Gregory CLEMENT
Hi Haojian,
Quoted 23 lines · Haojian Zhuang
Add new
ARCH_MULTI_V7_LPAEconfig. It will selectARM_LPAEonly bothARCH_MULTI_V6&ARCH_MULTI_V7is disabled.
ARCH_MULTI_V7means non-LPAE platform.Signed-off-by Haojian Zhuang <[email protected]>--- arch/arm/Kconfig | 9 ++++++++- arch/arm/mach-berlin/Kconfig | 2 +- arch/arm/mach-highbank/Kconfig | 2 +- arch/arm/mach-mvebu/Kconfig | 6 +++--- arch/arm/mach-omap2/Kconfig | 4 ++-- arch/arm/mach-qcom/Kconfig | 2 +- arch/arm/mach-shmobile/Kconfig | 2 +- arch/arm/mach-tegra/Kconfig | 2 +- arch/arm/mach-vexpress/Kconfig | 2 +- 9 files changed, 19 insertions(+), 12 deletions(-)arch/arm/Kconfig +0
-0arch/arm/Kconfig config ARCH_MULTI_V6 · line 921
Quoted 5 lines
arch/arm/Kconfig +1
-1@@ -918,12 +918,19 @@ config ARCH_MULTI_V6 select CPU_V6K config ARCH_MULTI_V7 - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)" + bool "ARMv7 non-LPAE based platforms (Cortex-A5/A8/A9, PJ4, Scorpion)"Actually some PJ4B are also non LPAE capable
Quoted 5 lines
arch/arm/Kconfig +0
-0default y select ARCH_MULTI_V6_V7 select CPU_V7 select HAVE_SMPQuoted 6 lines
Quoted 4 lines
arch/arm/Kconfig config ARCH_MULTI_V6 · line 928
Quoted 2 lines
arch/arm/Kconfig +2
-0+config ARCH_MULTI_V7_LPAE + bool "ARMv7 LPAE based platforms (Cortex-A7/A12/A15/A17, Brahma-B15, PJ4B, Krait)"Only Armada XP is LPAE capable, and and the CPU is not a "simple" PJ4B but a PJ4B-MP
Do you mind that I append
CPU_PJ4B_MP?Currently we make no difference in the code between PJ4B and PJ4B-MP. Moreover the
ARCH_MULTI_V7_LPAEvsARCH_MULTI_V7si done by SoC not by CPU.
Quoted 8 lines
Quoted 2 lines
Maybe I missed something, what is your proposal?
Since they're same between PJ4B & PJ4B-MP, I shouldn't append a new
PJ4B_MP.I'll only use both
ARCH_MULTI_V7&ARCH_MULTI_V7_LPAEas the precondition onARMADA_XP. I'll keepARCH_MULTI_V7as the precondition on other armada chips in mach-berlin directory.
In mach-mvebu actually
Quoted 3 lines
So when
multi_v7_lpae_defconfigis appended, onlyARMADA_XPis built from mach-berlin directory. Is it OK?
ARMADA_XP is in mach-mvebu directory, but beside this typo I am OK :)
By the way I am really happy to have the possibility to build now a multi_v7_lpae image.
Thanks,
Gregory
Quoted 4 lines
Regards
Haojian
Signature · 4 lines
Gregory Clement, Free Electrons Kernel, drivers, real-time and embedded Linux development, consulting, training and support. http://free-electrons.com
PATCH v3 3/13 ARM: hisi: add ARCH_HISI
In reply to Haojian ZhuangSince multiple ARCH configuration will be appended into mach-hisi directory, add ARCH_HISI as common configuration for different ARCH in mach-hisi.
--- arch/arm/Makefile | 2 +- arch/arm/mach-hisi/Kconfig | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-)
arch/arm/Makefile +1 -1
@@ -154,7 +154,7 @@ machine-$(CONFIG_ARCH_EP93XX) += ep93xx machine-$(CONFIG_ARCH_EXYNOS) += exynos machine-$(CONFIG_ARCH_GEMINI) += gemini machine-$(CONFIG_ARCH_HIGHBANK) += highbank -machine-$(CONFIG_ARCH_HI3xxx) += hisi +machine-$(CONFIG_ARCH_HISI) += hisi machine-$(CONFIG_ARCH_INTEGRATOR) += integrator machine-$(CONFIG_ARCH_IOP13XX) += iop13xx machine-$(CONFIG_ARCH_IOP32X) += iop32x
arch/arm/mach-hisi/Kconfig +14 -2
@@ -1,8 +1,16 @@ -config ARCH_HI3xxx - bool "Hisilicon Hi36xx/Hi37xx family" if ARCH_MULTI_V7 +config ARCH_HISI + bool "Hisilicon SoC Support" + depends on ARCH_MULTIPLATFORM select ARM_AMBA select ARM_GIC select ARM_TIMER_SP804 + +if ARCH_HISI + +menu "Hisilicon platform type" + +config ARCH_HI3xxx + bool "Hisilicon Hi36xx/Hi37xx family" if ARCH_MULTI_V7 select CACHE_L2X0 select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP
@@ -10,3 +18,7 @@ config ARCH_HI3xxx select PINCTRL_SINGLE help Support for Hisilicon Hi36xx/Hi37xx processor family + +endmenu + +endif
Signature · 1 line
1.8.3.2
PATCH v3 4/13 irq: gic: use mask field in GICC_IAR
In reply to Haojian ZhuangBit[9:0] is interrupt ID field in GICC_IAR. Bit[12:10] is CPU ID field, and others are reserved.
So we should use GICC_IAR_INTID to get interrupt ID. It's not a good way to use ~0x1c00 (CPU ID field) to get interrupt ID.
--- drivers/irqchip/irq-gic.c | 2 +- include/linux/irqchip/arm-gic.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic.c +1 -1
@@ -287,7 +287,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) do { irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); - irqnr = irqstat & ~0x1c00; + irqnr = irqstat & GICC_IAR_INTID; if (likely(irqnr > 15 && irqnr < 1021)) { irqnr = irq_find_mapping(gic->domain, irqnr);
include/linux/irqchip/arm-gic.h +2 -0
@@ -21,6 +21,8 @@#define GIC_CPU_ACTIVEPRIO 0xd0#define GIC_CPU_IDENT 0xfc +#define GICC_IAR_INTID 0x3ff +#define GIC_DIST_CTRL 0x000#define GIC_DIST_CTR 0x004#define GIC_DIST_IGROUP 0x080
Signature · 1 line
1.8.3.2
PATCH v3 5/13 irq: gic: support hip04 gic
In reply to Haojian ZhuangThere's a little difference between ARM GIC and HiP04 GIC.
* HiP04 GIC could support 16 cores at most, and ARM GIC could support 8 cores at most. So the difination on GIC_DIST_SGIR, GIC_DIST_SGI_PENDING_SET, GIC_DIST_SGI_PENDING_CLEAR
& GIC_DIST_TARGET registers are different since CPU interfaces are increased from 8-bit to 16-bit.
* HiP04 GIC could support 510 interrupts at most, and ARM GIC could support 1020 interrupts at most.
--- drivers/irqchip/irq-gic.c | 153 +++++++++++++++++++++++++++++++++------------- 1 file changed, 109 insertions(+), 44 deletions(-)
drivers/irqchip/irq-gic.c +109 -44
@@ -68,6 +68,8 @@ struct gic_chip_data {#ifdef CONFIG_GIC_NON_BANKED void __iomem *(*get_base)(union gic_base *);#endif +u32 nr_cpu_if; +u32 nr_if_per_reg; };static DEFINE_RAW_SPINLOCK (irq_controller_lock);
@@ -76,9 +78,14 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);* The GIC mapping of CPU interfaces does not necessarily match * the logical CPU numbering. Let's use a mapping as returned * by the GIC itself. +* +* Hisilicon HiP04 extends the number of CPU interface from 8 to 16. */ -#define NR_GIC_CPU_IF 8 -static u8 gic_cpu_map[NR_GIC_CPU_IF ]__read_mostly ; +#define NR_GIC_CPU_IF 16 +static u16 gic_cpu_map[NR_GIC_CPU_IF ]__read_mostly ; + +/* GIC register is always 32-bit long whatever it's in ARM64 or ARM32 */ +#define GIC_REG_BITS 32/* * Supported arch specific GIC irq extension.
@@ -242,19 +249,50 @@ static int gic_retrigger(struct irq_data *d) }#ifdef CONFIG_SMP +static inline u32 irq_to_core_offset (u32 i,u32 nr_cpu_if) +{ +if (nr_cpu_if ==8 ) { +/* ARM GIC, i / 4 * 4 */ +return ((i >>2 ) <<2 ); + } +/* HiP04 GIC (nr_cpu_if == 16), i / 2 * 4 */ +return ((i >>1 ) <<2 ); +} + +static inline u32 irq_to_core_shift (u32 i,u32 nr_cpu_if) +{ +if (nr_cpu_if ==8 ) { +/* ARM GIC, i % 4 * 8 */ +return ((i %4 ) <<3 ); + } +/* HiP04 GIC (nr_cpu_if == 16), i % 2 * 16 */ +return ((i %2 ) <<4 ); +} + +static inline u32 irq_to_core_mask (u32 i,u32 nr_cpu_if) +{ +u32 mask; +/* ARM GIC, nr_cpu_if == 8; HiP04 GIC, nr_cpu_if == 16 */ + mask = (1 << nr_cpu_if) -1 ; +return (mask <<irq_to_core_shift (i, nr_cpu_if)); +} +static int gic_set_affinity (struct irq_data *d,const struct cpumask *mask_val,bool force) { -void __iomem *reg =gic_dist_base (d) +GIC_DIST_TARGET + (gic_irq (d) & ~3 ); -unsigned int shift = (gic_irq (d) %4 ) *8 ; +void __iomem *reg; +unsigned int i =gic_irq (d); +unsigned int shift =irq_to_core_shift (i, gic_data[0 ].nr_cpu_if);unsigned int cpu =cpumask_any_and (mask_val, cpu_online_mask);u32 val, mask, bit; - -if (cpu >=NR_GIC_CPU_IF || cpu >= nr_cpu_ids) +if (cpu >= gic_data[0 ].nr_cpu_if || cpu >= nr_cpu_ids)return -EINVAL ; + reg =gic_dist_base (d) +GIC_DIST_TARGET + +irq_to_core_offset (i, gic_data[0 ].nr_cpu_if); +raw_spin_lock (&irq_controller_lock); - mask =0xff << shift; + mask =irq_to_core_mask (i, gic_data[0 ].nr_cpu_if); bit = gic_cpu_map[cpu] << shift; val =readl_relaxed (reg) & ~mask;writel_relaxed (val | bit, reg);
@@ -354,15 +392,16 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)irq_set_chained_handler (irq, gic_handle_cascade_irq); } -static u8 gic_get_cpumask (struct gic_chip_data *gic) +static u16 gic_get_cpumask (struct gic_chip_data *gic) {void __iomem *base =gic_data_dist_base (gic); -u32 mask, i; +u32 mask, i, j, nr_if = gic->nr_if_per_reg; -for (i = mask =0 ; i <32 ; i +=4 ) { - mask =readl_relaxed (base +GIC_DIST_TARGET + i); - mask |= mask >>16 ; - mask |= mask >>8 ; +/* get the number of CPU fields in GIC_DIST_TARGET register */ +for (i = mask =0 ; i <DIV_ROUND_UP (32 , nr_if); i++) { + mask =readl_relaxed (base +GIC_DIST_TARGET + i *4 ); +for (j =GIC_REG_BITS >>1 ; j >= gic->nr_cpu_if; j >>=1 ) + mask |= mask >> j;if (mask)break ; }
@@ -370,12 +409,16 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)if (!mask)pr_crit ("GIC CPU mask not found - kernel will fail to boot.\n" ); +/* ARM GIC needs 8-bit cpu mask, HiP04 GIC needs 16-bit cpu mask. */ +if (gic->nr_cpu_if ==8 ) + mask &=0xff ; +return mask; }static void __init gic_dist_init (struct gic_chip_data *gic) { -unsigned int i; +unsigned int i, nr_if = gic->nr_if_per_reg;u32 cpumask;unsigned int gic_irqs = gic->gic_irqs;void __iomem *base =gic_data_dist_base (gic);
@@ -392,23 +435,25 @@ static void __init gic_dist_init(struct gic_chip_data *gic)* Set all global interrupts to this CPU only. */ cpumask =gic_get_cpumask (gic); - cpumask |= cpumask <<8 ; - cpumask |= cpumask <<16 ; -for (i =32 ; i < gic_irqs; i +=4 ) -writel_relaxed (cpumask, base +GIC_DIST_TARGET + i *4 /4 ); +for (i = gic->nr_cpu_if; i <GIC_REG_BITS ; i <<=1 ) + cpumask |= cpumask << i; +for (i =32 / nr_if; i <DIV_ROUND_UP (gic_irqs, nr_if); i++) +writel_relaxed (cpumask, base +GIC_DIST_TARGET + i *4 );/* * Set priority on all global interrupts. */ -for (i =32 ; i < gic_irqs; i +=4 ) -writel_relaxed (0xa0a0a0a0 , base +GIC_DIST_PRI + i *4 /4 ); +for (i =32 / nr_if; i <DIV_ROUND_UP (gic_irqs,4 ); i++) +writel_relaxed (0xa0a0a0a0 , base +GIC_DIST_PRI + i *4 );/* * Disable all interrupts. Leave the PPI and SGIs alone * as these enables are banked registers. */ -for (i =32 ; i < gic_irqs; i +=32 ) -writel_relaxed (0xffffffff , base +GIC_DIST_ENABLE_CLEAR + i *4 /32 ); + i =32 /GIC_REG_BITS ; +for (; i <DIV_ROUND_UP (gic_irqs,GIC_REG_BITS ); i++) +writel_relaxed (0xffffffff , + base +GIC_DIST_ENABLE_CLEAR + i *4 );writel_relaxed (1 , base +GIC_DIST_CTRL ); }
@@ -423,7 +468,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)/* * Get what the GIC says our CPU mask is. */ -BUG_ON (cpu >=NR_GIC_CPU_IF ); +BUG_ON (cpu >= gic->nr_cpu_if); cpu_mask =gic_get_cpumask (gic); gic_cpu_map[cpu] = cpu_mask;
@@ -431,7 +476,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)* Clear our mask from the other map entries in case they're * still undefined. */ -for (i =0 ; i <NR_GIC_CPU_IF ; i++) +for (i =0 ; i < gic->nr_cpu_if; i++)if (i != cpu) gic_cpu_map[i] &= ~cpu_mask;
@@ -445,8 +490,8 @@ static void gic_cpu_init(struct gic_chip_data *gic)/* * Set priority on PPI and SGI interrupts */ -for (i =0 ; i <32 ; i +=4 ) -writel_relaxed (0xa0a0a0a0 , dist_base +GIC_DIST_PRI + i *4 /4 ); +for (i =0 ; i <DIV_ROUND_UP (32 ,4 ); i++) +writel_relaxed (0xa0a0a0a0 , dist_base +GIC_DIST_PRI + i *4 );writel_relaxed (0xf0 , base +GIC_CPU_PRIMASK );writel_relaxed (1 , base +GIC_CPU_CTRL );
@@ -467,7 +512,7 @@ void gic_cpu_if_down(void)*/ static void gic_dist_save (unsigned int gic_nr) { -unsigned int gic_irqs; +unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;void __iomem *dist_base;int i;
@@ -484,7 +529,7 @@ static void gic_dist_save(unsigned int gic_nr) gic_data[gic_nr].saved_spi_conf[i] =readl_relaxed (dist_base +GIC_DIST_CONFIG + i *4 ); -for (i =0 ; i <DIV_ROUND_UP (gic_irqs,4 ); i++) +for (i =0 ; i <DIV_ROUND_UP (gic_irqs, nr_if); i++) gic_data[gic_nr].saved_spi_target[i] =readl_relaxed (dist_base +GIC_DIST_TARGET + i *4 );
@@ -502,7 +547,7 @@ static void gic_dist_save(unsigned int gic_nr)*/ static void gic_dist_restore (unsigned int gic_nr) { -unsigned int gic_irqs; +unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;unsigned int i;void __iomem *dist_base;
@@ -525,7 +570,7 @@ static void gic_dist_restore(unsigned int gic_nr)writel_relaxed (0xa0a0a0a0 , dist_base +GIC_DIST_PRI + i *4 ); -for (i =0 ; i <DIV_ROUND_UP (gic_irqs,4 ); i++) +for (i =0 ; i <DIV_ROUND_UP (gic_irqs, nr_if); i++)writel_relaxed (gic_data[gic_nr].saved_spi_target[i], dist_base +GIC_DIST_TARGET + i *4 );
@@ -665,9 +710,15 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)*/ dmb (ishst); -/* this always happens on GIC0 */ -writel_relaxed (map <<16 | irq,gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT ); - +/* +* CPUTargetList -- bit[23:16] in GIC_DIST_SOFTINT in ARM GIC. +* bit[23:8] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC. +* NSATT -- bit[15] in GIC_DIST_SOFTINT in ARM GIC. +* bit[7] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC. +* this always happens on GIC0 +*/ +writel_relaxed (map << (16 +8 - gic_data[0 ].nr_cpu_if) | irq, +gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT ); raw_spin_unlock_irqrestore(&irq_controller_lock, flags); }#endif
@@ -681,10 +732,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)*/ void gic_send_sgi (unsigned int cpu_id,unsigned int irq) { -BUG_ON (cpu_id >=NR_GIC_CPU_IF ); +BUG_ON (cpu_id >= gic_data[0 ].nr_cpu_if); cpu_id =1 << cpu_id;/* this always happens on GIC0 */ -writel_relaxed ((cpu_id <<16 ) | irq,gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT ); +writel_relaxed ((cpu_id << (16 +8 - gic_data[0 ].nr_cpu_if)) | irq, +gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT ); }/*
@@ -700,7 +752,7 @@ int gic_get_cpu_id(unsigned int cpu) {unsigned int cpu_bit; -if (cpu >=NR_GIC_CPU_IF ) +if (cpu >= gic_data[0 ].nr_cpu_if)return -1 ; cpu_bit = gic_cpu_map[cpu];if (cpu_bit & (cpu_bit -1 ))
@@ -771,10 +823,10 @@ void gic_migrate_target(unsigned int new_cpu_id)*/ for (i =0 ; i <16 ; i +=4 ) {int j; - val =readl_relaxed (dist_base +GIC_DIST_SGI_PENDING_SET + i); + val =readl_relaxed (dist_base +GIC_DIST_PENDING_SET + i);if (!val)continue ; -writel_relaxed (val, dist_base +GIC_DIST_SGI_PENDING_CLEAR + i); +writel_relaxed (val, dist_base +GIC_DIST_PENDING_CLEAR + i);for (j = i; j < i +4 ; j++) {if (val &0xff ) writel_relaxed((1 << (new_cpu_id + 16)) | j,
@@ -931,7 +983,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,irq_hw_number_t hwirq_base;struct gic_chip_data *gic;int gic_irqs, irq_base, i; -int nr_routable_irqs; +int nr_routable_irqs, max_nr_irq;BUG_ON (gic_nr >=MAX_GIC_NR );
@@ -967,12 +1019,23 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,gic_set_base_accessor (gic, gic_get_common_base); } +if (of_device_is_compatible (node,"hisilicon,hip04-gic" )) { +/* HiP04 GIC supports 16 CPUs at most */ + gic->nr_cpu_if =16 ; + max_nr_irq =510 ; + }else { +/* ARM/Qualcomm GIC supports 8 CPUs at most */ + gic->nr_cpu_if =8 ; + max_nr_irq =1020 ; + } + gic->nr_if_per_reg =GIC_REG_BITS / gic->nr_cpu_if; +/* * Initialize the CPU interface map to all CPUs. * It will be refined as each CPU probes its ID. */ -for (i =0 ; i <NR_GIC_CPU_IF ; i++) - gic_cpu_map[i] =0xff ; +for (i =0 ; i < gic->nr_cpu_if; i++) + gic_cpu_map[i] = (1 << gic->nr_cpu_if) -1 ;/* * For primary GICs, skip over SGIs.
@@ -988,12 +1051,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,/* * Find out how many interrupts are supported. -* The GIC only supports up to 1020 interrupt sources. +* The ARM/Qualcomm GIC only supports up to 1020 interrupt sources. +* The HiP04 GIC only supports up to 510 interrupt sources. */ gic_irqs =readl_relaxed (gic_data_dist_base (gic) +GIC_DIST_CTR ) &0x1f ; gic_irqs = (gic_irqs +1 ) *32 ; -if (gic_irqs >1020 ) - gic_irqs =1020 ; +if (gic_irqs > max_nr_irq) + gic_irqs = max_nr_irq; gic->gic_irqs = gic_irqs; gic_irqs -= hwirq_base;/* calculate # of irqs to allocate */
@@ -1069,6 +1133,7 @@ gic_of_init(struct device_node *node, struct device_node *parent) }IRQCHIP_DECLARE (cortex_a15_gic,"arm,cortex-a15-gic" , gic_of_init);IRQCHIP_DECLARE (cortex_a9_gic,"arm,cortex-a9-gic" , gic_of_init); +IRQCHIP_DECLARE (hip04_gic,"hisilicon,hip04-gic" , gic_of_init);IRQCHIP_DECLARE (msm_8660_qgic,"qcom,msm-8660-qgic" , gic_of_init);IRQCHIP_DECLARE (msm_qgic2,"qcom,msm-qgic2" , gic_of_init);
Signature · 1 line
1.8.3.2
PATCH v3 5/13 irq: gic: support hip04 gic
Hi Haojian,
Quoted 4 lines · Haojian Zhuang
There's a little difference between ARM GIC and HiP04 GIC.
* HiP04 GIC could support 16 cores at most, and ARM GIC could support 8 cores at most. So the difination on
GIC_DIST_SGIR,
definitions of
Quoted 17 lines
GIC_DIST_SGI_PENDING_SET,GIC_DIST_SGI_PENDING_CLEAR
&GIC_DIST_TARGETregisters are different since CPU interfaces are increased from 8-bit to 16-bit.* HiP04 GIC could support 510 interrupts at most, and ARM GIC could support 1020 interrupts at most.
Signed-off-by Haojian Zhuang <[email protected]>--- drivers/irqchip/irq-gic.c | 153 +++++++++++++++++++++++++++++++++------------- 1 file changed, 109 insertions(+), 44 deletions(-)drivers/irqchip/irq-gic.c +0
-0
drivers/irqchip/irq-gic.c struct gic_chip_data { · line 72
Quoted 5 lines
drivers/irqchip/irq-gic.c +2
-0@@ -68,6 +68,8 @@ struct gic_chip_data {#ifdef CONFIG_GIC_NON_BANKED void __iomem *(*get_base)(union gic_base *);#endif +u32 nr_cpu_if; +u32 nr_if_per_reg;
Which register? Surely you can compute that at runtime.
Quoted 7 lines
drivers/irqchip/irq-gic.c +0
-0};static DEFINE_RAW_SPINLOCK (irq_controller_lock);@@ -76,9 +78,14 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);* The GIC mapping of CPU interfaces does not necessarily match * the logical CPU numbering. Let's use a mapping as returned * by the GIC itself.
drivers/irqchip/irq-gic.c static DEFINE_RAW_SPINLOCK(irq_controller_lock); · line 88
Quoted 10 lines
drivers/irqchip/irq-gic.c +7
-2+* +* Hisilicon HiP04 extends the number of CPU interface from 8 to 16. */ -#define NR_GIC_CPU_IF 8 -static u8 gic_cpu_map[NR_GIC_CPU_IF ]__read_mostly ; +#define NR_GIC_CPU_IF 16 +static u16 gic_cpu_map[NR_GIC_CPU_IF ]__read_mostly ; + +/* GIC register is always 32-bit long whatever it's in ARM64 or ARM32 */ +#define GIC_REG_BITS 32
What doesn this buy us? I'm not sure we gain much from it.
drivers/irqchip/irq-gic.c static int gic_retrigger(struct irq_data *d) · line 253
Quoted 8 lines
drivers/irqchip/irq-gic.c +2
-0/* * Supported arch specific GIC irq extension. @@ -242,19 +249,50 @@ static int gic_retrigger(struct irq_data *d) }#ifdef CONFIG_SMP +static inline u32 irq_to_core_offset (u32 i,u32 nr_cpu_if) +{
Make this function take an irq_data pointer, and use the accessor to find out about the number of CPU interfaces.
drivers/irqchip/irq-gic.c static int gic_retrigger(struct irq_data *d) · line 256
Quoted 3 lines
drivers/irqchip/irq-gic.c +3
-0+if (nr_cpu_if ==8 ) { +/* ARM GIC, i / 4 * 4 */ +return ((i >>2 ) <<2 );
Why does the comment has one expression and the code another? I know they give the same result, but this is pretty useless.
drivers/irqchip/irq-gic.c static int gic_retrigger(struct irq_data *d) · line 259
Quoted 3 lines
drivers/irqchip/irq-gic.c +3
-0+ } +/* HiP04 GIC (nr_cpu_if == 16), i / 2 * 4 */ +return ((i >>1 ) <<2 );
Same here.
drivers/irqchip/irq-gic.c static int gic_retrigger(struct irq_data *d) · line 263
Quoted 4 lines
drivers/irqchip/irq-gic.c +4
-0+} + +static inline u32 irq_to_core_shift (u32 i,u32 nr_cpu_if) +{
Same remarks as above.
drivers/irqchip/irq-gic.c static int gic_retrigger(struct irq_data *d) · line 273
Quoted 10 lines
drivers/irqchip/irq-gic.c +10
-0+if (nr_cpu_if ==8 ) { +/* ARM GIC, i % 4 * 8 */ +return ((i %4 ) <<3 ); + } +/* HiP04 GIC (nr_cpu_if == 16), i % 2 * 16 */ +return ((i %2 ) <<4 ); +} + +static inline u32 irq_to_core_mask (u32 i,u32 nr_cpu_if) +{
And here too.
Quoted 43 lines
drivers/irqchip/irq-gic.c +16
-9+u32 mask; +/* ARM GIC, nr_cpu_if == 8; HiP04 GIC, nr_cpu_if == 16 */ + mask = (1 << nr_cpu_if) -1 ; +return (mask <<irq_to_core_shift (i, nr_cpu_if)); +} +static int gic_set_affinity (struct irq_data *d,const struct cpumask *mask_val,bool force) { -void __iomem *reg =gic_dist_base (d) +GIC_DIST_TARGET + (gic_irq (d) & ~3 ); -unsigned int shift = (gic_irq (d) %4 ) *8 ; +void __iomem *reg; +unsigned int i =gic_irq (d); +unsigned int shift =irq_to_core_shift (i, gic_data[0 ].nr_cpu_if);unsigned int cpu =cpumask_any_and (mask_val, cpu_online_mask);u32 val, mask, bit; - -if (cpu >=NR_GIC_CPU_IF || cpu >= nr_cpu_ids) +if (cpu >= gic_data[0 ].nr_cpu_if || cpu >= nr_cpu_ids)return -EINVAL ; + reg =gic_dist_base (d) +GIC_DIST_TARGET + +irq_to_core_offset (i, gic_data[0 ].nr_cpu_if); +raw_spin_lock (&irq_controller_lock); - mask =0xff << shift; + mask =irq_to_core_mask (i, gic_data[0 ].nr_cpu_if); bit = gic_cpu_map[cpu] << shift; val =readl_relaxed (reg) & ~mask;writel_relaxed (val | bit, reg);@@ -354,15 +392,16 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)irq_set_chained_handler (irq, gic_handle_cascade_irq); } -static u8 gic_get_cpumask (struct gic_chip_data *gic) +static u16 gic_get_cpumask (struct gic_chip_data *gic) {void __iomem *base =gic_data_dist_base (gic); -u32 mask, i; +u32 mask, i, j, nr_if = gic->nr_if_per_reg; -for (i = mask =0 ; i <32 ; i +=4 ) { - mask =readl_relaxed (base +GIC_DIST_TARGET + i);
drivers/irqchip/irq-gic.c void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) · line 407
Quoted 10 lines
drivers/irqchip/irq-gic.c +5
-2- mask |= mask >>16 ; - mask |= mask >>8 ; +/* get the number of CPU fields in GIC_DIST_TARGET register */ +for (i = mask =0 ; i <DIV_ROUND_UP (32 , nr_if); i++) { + mask =readl_relaxed (base +GIC_DIST_TARGET + i *4 ); +for (j =GIC_REG_BITS >>1 ; j >= gic->nr_cpu_if; j >>=1 ) + mask |= mask >> j;if (mask)break ; }
This looks incredibly convoluted. How about something like the code below, which is way simpler and doesn't involve changing so much stuff (completely untested, of course):
int nr_target_regs = 32 / (gic->nr_cpu_if == 8 ? 4 : 2);
for (i = mask = 0; i < nr_target_regs; i++) {
mask = readl_relaxed(base + GIC_DIST_TARGET + i * 4);
mask |= mask >> 16;
if (gic->nr_cpu_if == 8)
mask |= mask >> 8;
if (mask)
break;
} Quoted 19 lines
drivers/irqchip/irq-gic.c +5
-1@@ -370,12 +409,16 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)if (!mask)pr_crit ("GIC CPU mask not found - kernel will fail to boot.\n" ); +/* ARM GIC needs 8-bit cpu mask, HiP04 GIC needs 16-bit cpu mask. */ +if (gic->nr_cpu_if ==8 ) + mask &=0xff ; +return mask; }static void __init gic_dist_init (struct gic_chip_data *gic) { -unsigned int i; +unsigned int i, nr_if = gic->nr_if_per_reg;u32 cpumask;unsigned int gic_irqs = gic->gic_irqs;void __iomem *base =gic_data_dist_base (gic);
drivers/irqchip/irq-gic.c static void __init gic_dist_init(struct gic_chip_data *gic) · line 439
Quoted 9 lines
drivers/irqchip/irq-gic.c +2
-4@@ -392,23 +435,25 @@ static void __init gic_dist_init(struct gic_chip_data *gic)* Set all global interrupts to this CPU only. */ cpumask =gic_get_cpumask (gic); - cpumask |= cpumask <<8 ; - cpumask |= cpumask <<16 ; -for (i =32 ; i < gic_irqs; i +=4 ) -writel_relaxed (cpumask, base +GIC_DIST_TARGET + i *4 /4 ); +for (i = gic->nr_cpu_if; i <GIC_REG_BITS ; i <<=1 ) + cpumask |= cpumask << i;
Really, you should stop adding bit arithmetics all over the place. You're just making a simple problem way too complex. What is wrong with:
if (gic->nr_cpu_if == 8)
cpumask |= cpumask << 8;?
drivers/irqchip/irq-gic.c static void __init gic_dist_init(struct gic_chip_data *gic) · line 441
Quoted 2 lines
drivers/irqchip/irq-gic.c +2
-0+for (i =32 / nr_if; i <DIV_ROUND_UP (gic_irqs, nr_if); i++) +writel_relaxed (cpumask, base +GIC_DIST_TARGET + i *4 );
Why do you need to DIV_ROUND_UP? GIC interrupts are always a multiple of 32.
Quoted 5 lines
drivers/irqchip/irq-gic.c +0
-2/* * Set priority on all global interrupts. */ -for (i =32 ; i < gic_irqs; i +=4 ) -writel_relaxed (0xa0a0a0a0 , base +GIC_DIST_PRI + i *4 /4 );
drivers/irqchip/irq-gic.c static void __init gic_dist_init(struct gic_chip_data *gic) · line 453
Quoted 10 lines
drivers/irqchip/irq-gic.c +3
-2+for (i =32 / nr_if; i <DIV_ROUND_UP (gic_irqs,4 ); i++) +writel_relaxed (0xa0a0a0a0 , base +GIC_DIST_PRI + i *4 );/* * Disable all interrupts. Leave the PPI and SGIs alone * as these enables are banked registers. */ -for (i =32 ; i < gic_irqs; i +=32 ) -writel_relaxed (0xffffffff , base +GIC_DIST_ENABLE_CLEAR + i *4 /32 ); + i =32 /GIC_REG_BITS ;
I predict this value to be the grand total of one.
Quoted 77 lines
drivers/irqchip/irq-gic.c +11
-10+for (; i <DIV_ROUND_UP (gic_irqs,GIC_REG_BITS ); i++) +writel_relaxed (0xffffffff , + base +GIC_DIST_ENABLE_CLEAR + i *4 );writel_relaxed (1 , base +GIC_DIST_CTRL ); }@@ -423,7 +468,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)/* * Get what the GIC says our CPU mask is. */ -BUG_ON (cpu >=NR_GIC_CPU_IF ); +BUG_ON (cpu >= gic->nr_cpu_if); cpu_mask =gic_get_cpumask (gic); gic_cpu_map[cpu] = cpu_mask;@@ -431,7 +476,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)* Clear our mask from the other map entries in case they're * still undefined. */ -for (i =0 ; i <NR_GIC_CPU_IF ; i++) +for (i =0 ; i < gic->nr_cpu_if; i++)if (i != cpu) gic_cpu_map[i] &= ~cpu_mask;@@ -445,8 +490,8 @@ static void gic_cpu_init(struct gic_chip_data *gic)/* * Set priority on PPI and SGI interrupts */ -for (i =0 ; i <32 ; i +=4 ) -writel_relaxed (0xa0a0a0a0 , dist_base +GIC_DIST_PRI + i *4 /4 ); +for (i =0 ; i <DIV_ROUND_UP (32 ,4 ); i++) +writel_relaxed (0xa0a0a0a0 , dist_base +GIC_DIST_PRI + i *4 );writel_relaxed (0xf0 , base +GIC_CPU_PRIMASK );writel_relaxed (1 , base +GIC_CPU_CTRL );@@ -467,7 +512,7 @@ void gic_cpu_if_down(void)*/ static void gic_dist_save (unsigned int gic_nr) { -unsigned int gic_irqs; +unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;void __iomem *dist_base;int i;@@ -484,7 +529,7 @@ static void gic_dist_save(unsigned int gic_nr) gic_data[gic_nr].saved_spi_conf[i] =readl_relaxed (dist_base +GIC_DIST_CONFIG + i *4 ); -for (i =0 ; i <DIV_ROUND_UP (gic_irqs,4 ); i++) +for (i =0 ; i <DIV_ROUND_UP (gic_irqs, nr_if); i++) gic_data[gic_nr].saved_spi_target[i] =readl_relaxed (dist_base +GIC_DIST_TARGET + i *4 );@@ -502,7 +547,7 @@ static void gic_dist_save(unsigned int gic_nr)*/ static void gic_dist_restore (unsigned int gic_nr) { -unsigned int gic_irqs; +unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;unsigned int i;void __iomem *dist_base;@@ -525,7 +570,7 @@ static void gic_dist_restore(unsigned int gic_nr)writel_relaxed (0xa0a0a0a0 , dist_base +GIC_DIST_PRI + i *4 ); -for (i =0 ; i <DIV_ROUND_UP (gic_irqs,4 ); i++) +for (i =0 ; i <DIV_ROUND_UP (gic_irqs, nr_if); i++)writel_relaxed (gic_data[gic_nr].saved_spi_target[i], dist_base +GIC_DIST_TARGET + i *4 );@@ -665,9 +710,15 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)*/ dmb (ishst); -/* this always happens on GIC0 */ -writel_relaxed (map <<16 | irq,gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT );
drivers/irqchip/irq-gic.c static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) · line 721
Quoted 10 lines
drivers/irqchip/irq-gic.c +9
-1- +/* +* CPUTargetList -- bit[23:16] in GIC_DIST_SOFTINT in ARM GIC. +* bit[23:8] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC. +* NSATT -- bit[15] in GIC_DIST_SOFTINT in ARM GIC. +* bit[7] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC. +* this always happens on GIC0 +*/ +writel_relaxed (map << (16 +8 - gic_data[0 ].nr_cpu_if) | irq, +gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT );
Make this two cases. This bit arithmetic makes it unreadable. Also, why does the comment makes the GIC_DIST_SOFTINT/HIP04_GIC_DIST_SOFTINT distinction, while the code only refers to GIC_DIST_SOFTINT?
Quoted 4 lines
drivers/irqchip/irq-gic.c +0
-0raw_spin_unlock_irqrestore(&irq_controller_lock, flags); }#endif
drivers/irqchip/irq-gic.c static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) · line 739
Quoted 10 lines
drivers/irqchip/irq-gic.c +3
-2@@ -681,10 +732,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)*/ void gic_send_sgi (unsigned int cpu_id,unsigned int irq) { -BUG_ON (cpu_id >=NR_GIC_CPU_IF ); +BUG_ON (cpu_id >= gic_data[0 ].nr_cpu_if); cpu_id =1 << cpu_id;/* this always happens on GIC0 */ -writel_relaxed ((cpu_id <<16 ) | irq,gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT ); +writel_relaxed ((cpu_id << (16 +8 - gic_data[0 ].nr_cpu_if)) | irq, +gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT );
Same here.
Quoted 13 lines
drivers/irqchip/irq-gic.c +1
-1}/* @@ -700,7 +752,7 @@ int gic_get_cpu_id(unsigned int cpu) {unsigned int cpu_bit; -if (cpu >=NR_GIC_CPU_IF ) +if (cpu >= gic_data[0 ].nr_cpu_if)return -1 ; cpu_bit = gic_cpu_map[cpu];if (cpu_bit & (cpu_bit -1 ))
drivers/irqchip/irq-gic.c void gic_migrate_target(unsigned int new_cpu_id) · line 829
Quoted 9 lines
drivers/irqchip/irq-gic.c +2
-2@@ -771,10 +823,10 @@ void gic_migrate_target(unsigned int new_cpu_id)*/ for (i =0 ; i <16 ; i +=4 ) {int j; - val =readl_relaxed (dist_base +GIC_DIST_SGI_PENDING_SET + i); + val =readl_relaxed (dist_base +GIC_DIST_PENDING_SET + i);if (!val)continue ; -writel_relaxed (val, dist_base +GIC_DIST_SGI_PENDING_CLEAR + i); +writel_relaxed (val, dist_base +GIC_DIST_PENDING_CLEAR + i);
What? Hell no. This is the SGI sources we're dealing with. And I'd expect your implementation to be quite different.
Quoted 17 lines
drivers/irqchip/irq-gic.c +2
-1for (j = i; j < i +4 ; j++) {if (val &0xff ) writel_relaxed((1 << (new_cpu_id + 16)) | j,@@ -931,7 +983,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,irq_hw_number_t hwirq_base;struct gic_chip_data *gic;int gic_irqs, irq_base, i; -int nr_routable_irqs; +int nr_routable_irqs, max_nr_irq;BUG_ON (gic_nr >=MAX_GIC_NR );@@ -967,12 +1019,23 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,gic_set_base_accessor (gic, gic_get_common_base); } +if (of_device_is_compatible (node,"hisilicon,hip04-gic" )) {
drivers/irqchip/irq-gic.c void __init gic_init_bases(unsigned int gic_nr, int irq_start, · line 1032
Quoted 10 lines
drivers/irqchip/irq-gic.c +10
-0+/* HiP04 GIC supports 16 CPUs at most */ + gic->nr_cpu_if =16 ; + max_nr_irq =510 ; + }else { +/* ARM/Qualcomm GIC supports 8 CPUs at most */ + gic->nr_cpu_if =8 ; + max_nr_irq =1020 ; + } + gic->nr_if_per_reg =GIC_REG_BITS / gic->nr_cpu_if; +
Loose this last line, and do the explicit computation. where needed. I don't this this adds anything.
Quoted 29 lines
drivers/irqchip/irq-gic.c +6
-5/* * Initialize the CPU interface map to all CPUs. * It will be refined as each CPU probes its ID. */ -for (i =0 ; i <NR_GIC_CPU_IF ; i++) - gic_cpu_map[i] =0xff ; +for (i =0 ; i < gic->nr_cpu_if; i++) + gic_cpu_map[i] = (1 << gic->nr_cpu_if) -1 ;/* * For primary GICs, skip over SGIs. @@ -988,12 +1051,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,/* * Find out how many interrupts are supported. -* The GIC only supports up to 1020 interrupt sources. +* The ARM/Qualcomm GIC only supports up to 1020 interrupt sources. +* The HiP04 GIC only supports up to 510 interrupt sources. */ gic_irqs =readl_relaxed (gic_data_dist_base (gic) +GIC_DIST_CTR ) &0x1f ; gic_irqs = (gic_irqs +1 ) *32 ; -if (gic_irqs >1020 ) - gic_irqs =1020 ; +if (gic_irqs > max_nr_irq) + gic_irqs = max_nr_irq; gic->gic_irqs = gic_irqs; gic_irqs -= hwirq_base;/* calculate # of irqs to allocate */
drivers/irqchip/irq-gic.c gic_of_init(struct device_node *node, struct device_node *parent) · line 1138
Quoted 6 lines
drivers/irqchip/irq-gic.c +1
-0@@ -1069,6 +1133,7 @@ gic_of_init(struct device_node *node, struct device_node *parent) }IRQCHIP_DECLARE (cortex_a15_gic,"arm,cortex-a15-gic" , gic_of_init);IRQCHIP_DECLARE (cortex_a9_gic,"arm,cortex-a9-gic" , gic_of_init); +IRQCHIP_DECLARE (hip04_gic,"hisilicon,hip04-gic" , gic_of_init);IRQCHIP_DECLARE (msm_8660_qgic,"qcom,msm-8660-qgic" , gic_of_init);IRQCHIP_DECLARE (msm_qgic2,"qcom,msm-qgic2" , gic_of_init);
Overall, there is still some work required to make this patch acceptable. The whole change could be much simpler and less controvertial if you didn't obfuscate the handling of the 16 CPU-IF case with so much bit arithmetic. Most of this code is on a slow path anyway, so you're not even optimizing anything that would be performance critical.
Cheers,
M.
Signature · 1 line
Jazz is not dead. It just smells funny.
PATCH v3 5/13 irq: gic: support hip04 gic
Quoted 20 lines · Marc Zyngier
Hi Haojian,
Quoted 4 lines · Haojian Zhuang
There's a little difference between ARM GIC and HiP04 GIC.
* HiP04 GIC could support 16 cores at most, and ARM GIC could support 8 cores at most. So the difination on
GIC_DIST_SGIR,definitions of
Quoted 12 lines
GIC_DIST_SGI_PENDING_SET,GIC_DIST_SGI_PENDING_CLEAR
&GIC_DIST_TARGETregisters are different since CPU interfaces are increased from 8-bit to 16-bit.* HiP04 GIC could support 510 interrupts at most, and ARM GIC could support 1020 interrupts at most.
Signed-off-by Haojian Zhuang <[email protected]>--- drivers/irqchip/irq-gic.c | 153 +++++++++++++++++++++++++++++++++------------- 1 file changed, 109 insertions(+), 44 deletions(-)
Quoted 12 lines
drivers/irqchip/irq-gic.c struct gic_chip_data { · line 72
Quoted 10 lines
drivers/irqchip/irq-gic.c +2
-0@@ -68,6 +68,8 @@ struct gic_chip_data {#ifdef CONFIG_GIC_NON_BANKED void __iomem *(*get_base)(union gic_base *);#endif +u32 nr_cpu_if; +u32 nr_if_per_reg;Which register? Surely you can compute that at runtime.
Yes, I can compute it at runtime. I'll change it.
Quoted 12 lines
Quoted 12 lines
drivers/irqchip/irq-gic.c +2
-1};static DEFINE_RAW_SPINLOCK (irq_controller_lock);@@ -76,9 +78,14 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);* The GIC mapping of CPU interfaces does not necessarily match * the logical CPU numbering. Let's use a mapping as returned * by the GIC itself. +* +* Hisilicon HiP04 extends the number of CPU interface from 8 to 16. */ -#define NR_GIC_CPU_IF 8
Quoted 8 lines
drivers/irqchip/irq-gic.c static DEFINE_RAW_SPINLOCK(irq_controller_lock); · line 88
Quoted 6 lines
drivers/irqchip/irq-gic.c +5
-1-static u8 gic_cpu_map[NR_GIC_CPU_IF ]__read_mostly ; +#define NR_GIC_CPU_IF 16 +static u16 gic_cpu_map[NR_GIC_CPU_IF ]__read_mostly ; + +/* GIC register is always 32-bit long whatever it's in ARM64 or ARM32 */ +#define GIC_REG_BITS 32What doesn this buy us? I'm not sure we gain much from it.
OK. I'll remove it.
Quoted 6 lines
Quoted 6 lines
drivers/irqchip/irq-gic.c +0
-0/* * Supported arch specific GIC irq extension. @@ -242,19 +249,50 @@ static int gic_retrigger(struct irq_data *d) }
Quoted 6 lines
drivers/irqchip/irq-gic.c static int gic_retrigger(struct irq_data *d) · line 253
Quoted 3 lines
drivers/irqchip/irq-gic.c +2
-0#ifdef CONFIG_SMP +static inline u32 irq_to_core_offset (u32 i,u32 nr_cpu_if) +{Make this function take an
irq_datapointer, and use the accessor to find out about the number of CPU interfaces.
Oh. No problem.
Quoted 8 lines
drivers/irqchip/irq-gic.c static int gic_retrigger(struct irq_data *d) · line 256
Quoted 4 lines
drivers/irqchip/irq-gic.c +3
-0+if (nr_cpu_if ==8 ) { +/* ARM GIC, i / 4 * 4 */ +return ((i >>2 ) <<2 );Why does the comment has one expression and the code another? I know they give the same result, but this is pretty useless.
Yes, I'll do.
Quoted 60 lines
Quoted 44 lines
drivers/irqchip/irq-gic.c +16
-9+u32 mask; +/* ARM GIC, nr_cpu_if == 8; HiP04 GIC, nr_cpu_if == 16 */ + mask = (1 << nr_cpu_if) -1 ; +return (mask <<irq_to_core_shift (i, nr_cpu_if)); +} +static int gic_set_affinity (struct irq_data *d,const struct cpumask *mask_val,bool force) { -void __iomem *reg =gic_dist_base (d) +GIC_DIST_TARGET + (gic_irq (d) & ~3 ); -unsigned int shift = (gic_irq (d) %4 ) *8 ; +void __iomem *reg; +unsigned int i =gic_irq (d); +unsigned int shift =irq_to_core_shift (i, gic_data[0 ].nr_cpu_if);unsigned int cpu =cpumask_any_and (mask_val, cpu_online_mask);u32 val, mask, bit; - -if (cpu >=NR_GIC_CPU_IF || cpu >= nr_cpu_ids) +if (cpu >= gic_data[0 ].nr_cpu_if || cpu >= nr_cpu_ids)return -EINVAL ; + reg =gic_dist_base (d) +GIC_DIST_TARGET + +irq_to_core_offset (i, gic_data[0 ].nr_cpu_if); +raw_spin_lock (&irq_controller_lock); - mask =0xff << shift; + mask =irq_to_core_mask (i, gic_data[0 ].nr_cpu_if); bit = gic_cpu_map[cpu] << shift; val =readl_relaxed (reg) & ~mask;writel_relaxed (val | bit, reg);@@ -354,15 +392,16 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)irq_set_chained_handler (irq, gic_handle_cascade_irq); } -static u8 gic_get_cpumask (struct gic_chip_data *gic) +static u16 gic_get_cpumask (struct gic_chip_data *gic) {void __iomem *base =gic_data_dist_base (gic); -u32 mask, i; +u32 mask, i, j, nr_if = gic->nr_if_per_reg; -for (i = mask =0 ; i <32 ; i +=4 ) { - mask =readl_relaxed (base +GIC_DIST_TARGET + i);drivers/irqchip/irq-gic.c void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) · line 407
Quoted 10 lines
drivers/irqchip/irq-gic.c +5
-2- mask |= mask >>16 ; - mask |= mask >>8 ; +/* get the number of CPU fields in GIC_DIST_TARGET register */ +for (i = mask =0 ; i <DIV_ROUND_UP (32 , nr_if); i++) { + mask =readl_relaxed (base +GIC_DIST_TARGET + i *4 ); +for (j =GIC_REG_BITS >>1 ; j >= gic->nr_cpu_if; j >>=1 ) + mask |= mask >> j;if (mask)break ; }This looks incredibly convoluted. How about something like the code below, which is way simpler and doesn't involve changing so much stuff (completely untested, of course):
int
nr_target_regs= 32 / (gic->nr_cpu_if== 8 ? 4 : 2);
Quoted 9 lines
for (i = mask = 0; i < nr_target_regs; i++) {
mask = readl_relaxed(base + GIC_DIST_TARGET + i * 4);
mask |= mask >> 16;
if (gic->nr_cpu_if == 8)
mask |= mask >> 8;
if (mask)
break;
}I'll change it.
Quoted 34 lines
Quoted 20 lines
drivers/irqchip/irq-gic.c +5
-1@@ -370,12 +409,16 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)if (!mask)pr_crit ("GIC CPU mask not found - kernel will fail to boot.\n" ); +/* ARM GIC needs 8-bit cpu mask, HiP04 GIC needs 16-bit cpu mask. */ +if (gic->nr_cpu_if ==8 ) + mask &=0xff ; +return mask; }static void __init gic_dist_init (struct gic_chip_data *gic) { -unsigned int i; +unsigned int i, nr_if = gic->nr_if_per_reg;u32 cpumask;unsigned int gic_irqs = gic->gic_irqs;void __iomem *base =gic_data_dist_base (gic);drivers/irqchip/irq-gic.c static void __init gic_dist_init(struct gic_chip_data *gic) · line 439
Quoted 9 lines
drivers/irqchip/irq-gic.c +2
-4@@ -392,23 +435,25 @@ static void __init gic_dist_init(struct gic_chip_data *gic)* Set all global interrupts to this CPU only. */ cpumask =gic_get_cpumask (gic); - cpumask |= cpumask <<8 ; - cpumask |= cpumask <<16 ; -for (i =32 ; i < gic_irqs; i +=4 ) -writel_relaxed (cpumask, base +GIC_DIST_TARGET + i *4 /4 ); +for (i = gic->nr_cpu_if; i <GIC_REG_BITS ; i <<=1 ) + cpumask |= cpumask << i;Really, you should stop adding bit arithmetics all over the place. You're just making a simple problem way too complex. What is wrong with:
Quoted 4 lines
if (gic->nr_cpu_if == 8) cpumask |= cpumask << 8;?
I'll use simple way to express it.
Quoted 7 lines
drivers/irqchip/irq-gic.c static void __init gic_dist_init(struct gic_chip_data *gic) · line 441
Quoted 3 lines
drivers/irqchip/irq-gic.c +2
-0+for (i =32 / nr_if; i <DIV_ROUND_UP (gic_irqs, nr_if); i++) +writel_relaxed (cpumask, base +GIC_DIST_TARGET + i *4 );Why do you need to
DIV_ROUND_UP? GIC interrupts are always a multiple of 32.
OK. I'll remove it.
Quoted 93 lines
Quoted 5 lines
drivers/irqchip/irq-gic.c +0
-2/* * Set priority on all global interrupts. */ -for (i =32 ; i < gic_irqs; i +=4 ) -writel_relaxed (0xa0a0a0a0 , base +GIC_DIST_PRI + i *4 /4 );drivers/irqchip/irq-gic.c static void __init gic_dist_init(struct gic_chip_data *gic) · line 453
Quoted 10 lines
drivers/irqchip/irq-gic.c +3
-2+for (i =32 / nr_if; i <DIV_ROUND_UP (gic_irqs,4 ); i++) +writel_relaxed (0xa0a0a0a0 , base +GIC_DIST_PRI + i *4 );/* * Disable all interrupts. Leave the PPI and SGIs alone * as these enables are banked registers. */ -for (i =32 ; i < gic_irqs; i +=32 ) -writel_relaxed (0xffffffff , base +GIC_DIST_ENABLE_CLEAR + i *4 /32 ); + i =32 /GIC_REG_BITS ;I predict this value to be the grand total of one.
Quoted 75 lines
drivers/irqchip/irq-gic.c +11
-8+for (; i <DIV_ROUND_UP (gic_irqs,GIC_REG_BITS ); i++) +writel_relaxed (0xffffffff , + base +GIC_DIST_ENABLE_CLEAR + i *4 );writel_relaxed (1 , base +GIC_DIST_CTRL ); }@@ -423,7 +468,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)/* * Get what the GIC says our CPU mask is. */ -BUG_ON (cpu >=NR_GIC_CPU_IF ); +BUG_ON (cpu >= gic->nr_cpu_if); cpu_mask =gic_get_cpumask (gic); gic_cpu_map[cpu] = cpu_mask;@@ -431,7 +476,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)* Clear our mask from the other map entries in case they're * still undefined. */ -for (i =0 ; i <NR_GIC_CPU_IF ; i++) +for (i =0 ; i < gic->nr_cpu_if; i++)if (i != cpu) gic_cpu_map[i] &= ~cpu_mask;@@ -445,8 +490,8 @@ static void gic_cpu_init(struct gic_chip_data *gic)/* * Set priority on PPI and SGI interrupts */ -for (i =0 ; i <32 ; i +=4 ) -writel_relaxed (0xa0a0a0a0 , dist_base +GIC_DIST_PRI + i *4 /4 ); +for (i =0 ; i <DIV_ROUND_UP (32 ,4 ); i++) +writel_relaxed (0xa0a0a0a0 , dist_base +GIC_DIST_PRI + i *4 );writel_relaxed (0xf0 , base +GIC_CPU_PRIMASK );writel_relaxed (1 , base +GIC_CPU_CTRL );@@ -467,7 +512,7 @@ void gic_cpu_if_down(void)*/ static void gic_dist_save (unsigned int gic_nr) { -unsigned int gic_irqs; +unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;void __iomem *dist_base;int i;@@ -484,7 +529,7 @@ static void gic_dist_save(unsigned int gic_nr) gic_data[gic_nr].saved_spi_conf[i] =readl_relaxed (dist_base +GIC_DIST_CONFIG + i *4 ); -for (i =0 ; i <DIV_ROUND_UP (gic_irqs,4 ); i++) +for (i =0 ; i <DIV_ROUND_UP (gic_irqs, nr_if); i++) gic_data[gic_nr].saved_spi_target[i] =readl_relaxed (dist_base +GIC_DIST_TARGET + i *4 );@@ -502,7 +547,7 @@ static void gic_dist_save(unsigned int gic_nr)*/ static void gic_dist_restore (unsigned int gic_nr) { -unsigned int gic_irqs; +unsigned int gic_irqs, nr_if = gic_data[gic_nr].nr_if_per_reg;unsigned int i;void __iomem *dist_base;@@ -525,7 +570,7 @@ static void gic_dist_restore(unsigned int gic_nr)writel_relaxed (0xa0a0a0a0 , dist_base +GIC_DIST_PRI + i *4 ); -for (i =0 ; i <DIV_ROUND_UP (gic_irqs,4 ); i++) +for (i =0 ; i <DIV_ROUND_UP (gic_irqs, nr_if); i++)writel_relaxed (gic_data[gic_nr].saved_spi_target[i], dist_base +GIC_DIST_TARGET + i *4 );@@ -665,9 +710,15 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)*/ dmb (ishst);
Quoted 16 lines
drivers/irqchip/irq-gic.c static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) · line 721
Quoted 12 lines
drivers/irqchip/irq-gic.c +9
-3-/* this always happens on GIC0 */ -writel_relaxed (map <<16 | irq,gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT ); - +/* +* CPUTargetList -- bit[23:16] in GIC_DIST_SOFTINT in ARM GIC. +* bit[23:8] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC. +* NSATT -- bit[15] in GIC_DIST_SOFTINT in ARM GIC. +* bit[7] in HIP04_GIC_DIST_SOFTINT in HiP04 GIC. +* this always happens on GIC0 +*/ +writel_relaxed (map << (16 +8 - gic_data[0 ].nr_cpu_if) | irq, +gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT );Make this two cases. This bit arithmetic makes it unreadable. Also, why does the comment makes the GIC_DIST_SOFTINT/HIP04_GIC_DIST_SOFTINT distinction, while the code only refers to
GIC_DIST_SOFTINT?
OK. I'll make it simpler.
Quoted 60 lines
Quoted 5 lines
drivers/irqchip/irq-gic.c +0
-0raw_spin_unlock_irqrestore(&irq_controller_lock, flags); }#endif drivers/irqchip/irq-gic.c static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) · line 739
Quoted 10 lines
drivers/irqchip/irq-gic.c +3
-2@@ -681,10 +732,11 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)*/ void gic_send_sgi (unsigned int cpu_id,unsigned int irq) { -BUG_ON (cpu_id >=NR_GIC_CPU_IF ); +BUG_ON (cpu_id >= gic_data[0 ].nr_cpu_if); cpu_id =1 << cpu_id;/* this always happens on GIC0 */ -writel_relaxed ((cpu_id <<16 ) | irq,gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT ); +writel_relaxed ((cpu_id << (16 +8 - gic_data[0 ].nr_cpu_if)) | irq, +gic_data_dist_base (&gic_data[0 ]) +GIC_DIST_SOFTINT );Same here.
Quoted 13 lines
drivers/irqchip/irq-gic.c +1
-1}/* @@ -700,7 +752,7 @@ int gic_get_cpu_id(unsigned int cpu) {unsigned int cpu_bit; -if (cpu >=NR_GIC_CPU_IF ) +if (cpu >= gic_data[0 ].nr_cpu_if)return -1 ; cpu_bit = gic_cpu_map[cpu];if (cpu_bit & (cpu_bit -1 ))drivers/irqchip/irq-gic.c void gic_migrate_target(unsigned int new_cpu_id) · line 829
Quoted 9 lines
drivers/irqchip/irq-gic.c +2
-2@@ -771,10 +823,10 @@ void gic_migrate_target(unsigned int new_cpu_id)*/ for (i =0 ; i <16 ; i +=4 ) {int j; - val =readl_relaxed (dist_base +GIC_DIST_SGI_PENDING_SET + i); + val =readl_relaxed (dist_base +GIC_DIST_PENDING_SET + i);if (!val)continue ; -writel_relaxed (val, dist_base +GIC_DIST_SGI_PENDING_CLEAR + i); +writel_relaxed (val, dist_base +GIC_DIST_PENDING_CLEAR + i);What? Hell no. This is the SGI sources we're dealing with. And I'd expect your implementation to be quite different.
Quoted 16 lines
drivers/irqchip/irq-gic.c +1
-1for (j = i; j < i +4 ; j++) {if (val &0xff ) writel_relaxed((1 << (new_cpu_id + 16)) | j,@@ -931,7 +983,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,irq_hw_number_t hwirq_base;struct gic_chip_data *gic;int gic_irqs, irq_base, i; -int nr_routable_irqs; +int nr_routable_irqs, max_nr_irq;BUG_ON (gic_nr >=MAX_GIC_NR );@@ -967,12 +1019,23 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,gic_set_base_accessor (gic, gic_get_common_base); }
Quoted 14 lines
drivers/irqchip/irq-gic.c void __init gic_init_bases(unsigned int gic_nr, int irq_start, · line 1032
Quoted 11 lines
drivers/irqchip/irq-gic.c +11
-0+if (of_device_is_compatible (node,"hisilicon,hip04-gic" )) { +/* HiP04 GIC supports 16 CPUs at most */ + gic->nr_cpu_if =16 ; + max_nr_irq =510 ; + }else { +/* ARM/Qualcomm GIC supports 8 CPUs at most */ + gic->nr_cpu_if =8 ; + max_nr_irq =1020 ; + } + gic->nr_if_per_reg =GIC_REG_BITS / gic->nr_cpu_if; +Loose this last line, and do the explicit computation. where needed. I don't this this adds anything.
OK.
Quoted 49 lines
Quoted 30 lines
drivers/irqchip/irq-gic.c +6
-5/* * Initialize the CPU interface map to all CPUs. * It will be refined as each CPU probes its ID. */ -for (i =0 ; i <NR_GIC_CPU_IF ; i++) - gic_cpu_map[i] =0xff ; +for (i =0 ; i < gic->nr_cpu_if; i++) + gic_cpu_map[i] = (1 << gic->nr_cpu_if) -1 ;/* * For primary GICs, skip over SGIs. @@ -988,12 +1051,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,/* * Find out how many interrupts are supported. -* The GIC only supports up to 1020 interrupt sources. +* The ARM/Qualcomm GIC only supports up to 1020 interrupt sources. +* The HiP04 GIC only supports up to 510 interrupt sources. */ gic_irqs =readl_relaxed (gic_data_dist_base (gic) +GIC_DIST_CTR ) &0x1f ; gic_irqs = (gic_irqs +1 ) *32 ; -if (gic_irqs >1020 ) - gic_irqs =1020 ; +if (gic_irqs > max_nr_irq) + gic_irqs = max_nr_irq; gic->gic_irqs = gic_irqs; gic_irqs -= hwirq_base;/* calculate # of irqs to allocate */ drivers/irqchip/irq-gic.c gic_of_init(struct device_node *node, struct device_node *parent) · line 1138
Quoted 6 lines
drivers/irqchip/irq-gic.c +1
-0@@ -1069,6 +1133,7 @@ gic_of_init(struct device_node *node, struct device_node *parent) }IRQCHIP_DECLARE (cortex_a15_gic,"arm,cortex-a15-gic" , gic_of_init);IRQCHIP_DECLARE (cortex_a9_gic,"arm,cortex-a9-gic" , gic_of_init); +IRQCHIP_DECLARE (hip04_gic,"hisilicon,hip04-gic" , gic_of_init);IRQCHIP_DECLARE (msm_8660_qgic,"qcom,msm-8660-qgic" , gic_of_init);IRQCHIP_DECLARE (msm_qgic2,"qcom,msm-qgic2" , gic_of_init);Overall, there is still some work required to make this patch acceptable. The whole change could be much simpler and less controvertial if you didn't obfuscate the handling of the 16 CPU-IF case with so much bit arithmetic. Most of this code is on a slow path anyway, so you're not even optimizing anything that would be performance critical.
Cheers,
M.--
Jazz is not dead. It just smells funny.
PATCH v3 6/13 ARM: mcpm: support 4 clusters in HiP04
In reply to Haojian ZhuangSince 16 Cortex-A15 cores are used in HiP04 SoC, enlarge the maximum clusters from 2 to 4 if HiP04 SoC is built without CONFIG_BIG_LITTLE.
--- arch/arm/Kconfig | 8 ++++++++ arch/arm/include/asm/mcpm.h | 5 +++++ 2 files changed, 13 insertions(+)
arch/arm/Kconfig +8 -0
@@ -1571,6 +1571,14 @@ config MCPM for (multi-)cluster based systems, such as big.LITTLE based systems. +config MCPM_QUAD_CLUSTER + bool "Enable Quad clusters in MPCM" + depends on MCPM + default n + help + This option enables quad clusters in MCPM. Quad clusters exist + in HiP04 SoC. + config BIG_LITTLE bool "big.LITTLE support (Experimental)" depends on CPU_V7 && SMP
arch/arm/include/asm/mcpm.h +5 -0
@@ -20,7 +20,12 @@* to consider dynamic allocation. */ #define MAX_CPUS_PER_CLUSTER 4 + +#ifdef CONFIG_MCPM_QUAD_CLUSTER +#define MAX_NR_CLUSTERS 4 +#else #define MAX_NR_CLUSTERS 2 +#endif #ifndef __ASSEMBLY__
Signature · 1 line
1.8.3.2
PATCH v3 6/13 ARM: mcpm: support 4 clusters in HiP04
Quoted 2 lines · Haojian Zhuang
Since 16 Cortex-A15 cores are used in HiP04 SoC, enlarge the maximum clusters from 2 to 4 if HiP04 SoC is built without
CONFIG_BIG_LITTLE.
Why "... if HiP04 SoC is built without CONFIG_BIG_LITTLE" ? That statement makes no sense. As mentioned before, if you have a multi-platform kernel config with CONFIG_BIG_LITTLE included, there is no reason for not supporting quad cluster platforms at the same time.
FYI you might want to have a look at patch #8032 in RMK's patch system that removes a build-time MCPM dependency from the b.L switcher.
Quoted 1 line
Signed-off-by Haojian Zhuang <[email protected]>
More comments below.
Quoted 10 lines
--- arch/arm/Kconfig | 8 ++++++++ arch/arm/include/asm/mcpm.h | 5 +++++ 2 files changed, 13 insertions(+)arch/arm/Kconfig +0
-0
arch/arm/Kconfig config MCPM · line 1575
Quoted 5 lines
arch/arm/Kconfig +2
-0@@ -1571,6 +1571,14 @@ config MCPM for (multi-)cluster based systems, such as big.LITTLE based systems. +config MCPM_QUAD_CLUSTER + bool "Enable Quad clusters in MPCM"
s/MPCM/MCPM/
Yet you should not provide any prompt text here. This is way too technical to leave to the user configuring the kernel to decide. Instead, the actual platform needing this feature should select this config symbol directly.
arch/arm/Kconfig config MCPM · line 1577
Quoted 2 lines
arch/arm/Kconfig +2
-0+ depends on MCPM + default n
The default is already n, so no need to explicitly default to the default's default.
arch/arm/Kconfig config MCPM · line 1580
Quoted 3 lines
arch/arm/Kconfig +3
-0+ help + This option enables quad clusters in MCPM. Quad clusters exist + in HiP04 SoC.
Please refrain from listing SoCs here.
Quoted 23 lines
arch/arm/Kconfig +0
-0config BIG_LITTLE bool "big.LITTLE support (Experimental)" depends on CPU_V7 && SMParch/arm/include/asm/mcpm.h +5
-0@@ -20,7 +20,12 @@* to consider dynamic allocation. */ #define MAX_CPUS_PER_CLUSTER 4 + +#ifdef CONFIG_MCPM_QUAD_CLUSTER +#define MAX_NR_CLUSTERS 4 +#else #define MAX_NR_CLUSTERS 2 +#endif #ifndef __ASSEMBLY__Signature · 1 line
1.8.3.2
PATCH v3 7/13 ARM: hisi: add hip04 SoC support
In reply to Haojian ZhuangHisilicon Hi3xxx is based on Cortex A9 Core. Now HiP04 SoC is based on Cortex A15 Core. Since multiple clusters is used in HiP04 SoC, it could be based on MCPM.
And HiP04 supports LPAE to support large memory.
--- arch/arm/Kconfig | 2 +- arch/arm/mach-hisi/Kconfig | 9 +- arch/arm/mach-hisi/Makefile | 1 + arch/arm/mach-hisi/core.h | 2 + arch/arm/mach-hisi/hisilicon.c | 12 ++ arch/arm/mach-hisi/platmcpm.c | 334 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 358 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-hisi/platmcpm.c
arch/arm/Kconfig +1 -1
@@ -1113,7 +1113,7 @@ source arch/arm/mm/Kconfig config ARM_NR_BANKS int - default 16 if ARCH_EP93XX + default 16 if ARCH_EP93XX || ARCH_HIP04 default 8 config IWMMXT
arch/arm/mach-hisi/Kconfig +8 -1
@@ -17,7 +17,14 @@ config ARCH_HI3xxx select PINCTRL select PINCTRL_SINGLE help - Support for Hisilicon Hi36xx/Hi37xx processor family + Support for Hisilicon Hi36xx/Hi37xx SoC family + +config ARCH_HIP04 + bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7_LPAE + select HAVE_ARM_ARCH_TIMER + select MCPM if SMP + help + Support for Hisilicon HiP04 SoC family endmenu
arch/arm/mach-hisi/Makefile +1 -0
@@ -3,4 +3,5 @@ # obj-y += hisilicon.o +obj-$(CONFIG_MCPM) += platmcpm.o obj-$(CONFIG_SMP) += platsmp.o hotplug.o
arch/arm/mach-hisi/core.h +2 -0
@@ -12,4 +12,6 @@ extern void hi3xxx_cpu_die(unsigned int cpu);extern int hi3xxx_cpu_kill (unsigned int cpu);extern void hi3xxx_set_cpu (int cpu,bool enable); +extern bool __init hip04_smp_init_ops (void ); +#endif
arch/arm/mach-hisi/hisilicon.c +12 -0
@@ -88,3 +88,15 @@ DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)") .smp = smp_ops(hi3xxx_smp_ops), .restart = hi3xxx_restart, MACHINE_END + +#ifdef CONFIG_ARCH_HIP04 +static const char *hip04_compat[]__initconst = { +"hisilicon,hip04-d01" , +NULL , +}; + +DT_MACHINE_START (HIP04 ,"Hisilicon HiP04 (Flattened Device Tree)" ) + .dt_compat = hip04_compat, + .smp_init =smp_init_ops (hip04_smp_init_ops), +MACHINE_END +#endif
arch/arm/mach-hisi/platmcpm.c new file +334 -0
334 lines not on this page · raw message
Signature · 1 line
1.8.3.2
PATCH v3 7/13 ARM: hisi: add hip04 SoC support
Quoted 7 lines · Haojian Zhuang
Hisilicon Hi3xxx is based on Cortex A9 Core. Now HiP04 SoC is based on Cortex A15 Core. Since multiple clusters is used in HiP04 SoC, it could be based on MCPM.
And HiP04 supports LPAE to support large memory.
Signed-off-by Haojian Zhuang <[email protected]>
I'm providing review comments on the MCPM parts only.
Quoted 28 lines
--- arch/arm/Kconfig | 2 +- arch/arm/mach-hisi/Kconfig | 9 +- arch/arm/mach-hisi/Makefile | 1 + arch/arm/mach-hisi/core.h | 2 + arch/arm/mach-hisi/hisilicon.c | 12 ++ arch/arm/mach-hisi/platmcpm.c | 334 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 358 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-hisi/platmcpm.carch/arm/Kconfig +1
-1@@ -1113,7 +1113,7 @@ source arch/arm/mm/Kconfig config ARM_NR_BANKS int - default 16 if ARCH_EP93XX + default 16 if ARCH_EP93XX || ARCH_HIP04 default 8 config IWMMXTarch/arm/mach-hisi/Kconfig +0
-0
arch/arm/mach-hisi/Kconfig config ARCH_HI3xxx · line 25
Quoted 10 lines
arch/arm/mach-hisi/Kconfig +6
-1@@ -17,7 +17,14 @@ config ARCH_HI3xxx select PINCTRL select PINCTRL_SINGLE help - Support for Hisilicon Hi36xx/Hi37xx processor family + Support for Hisilicon Hi36xx/Hi37xx SoC family + +config ARCH_HIP04 + bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7_LPAE + select HAVE_ARM_ARCH_TIMER + select MCPM if SMP
This is where you should select MCPM_QUAD_CLUSTER as well.
Quoted 5 lines
arch/arm/mach-hisi/Kconfig +2
-0+ help + Support for Hisilicon HiP04 SoC family endmenu
[...]
Quoted 104 lines
arch/arm/mach-hisi/platmcpm.c new file +98
-0@@ -0,0 +1,334 @@ +/* +* Copyright (c) 2013-2014 Linaro Ltd. +* Copyright (c) 2013-2014 Hisilicon Limited. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +*/ +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/memblock.h> +#include <linux/of_address.h> + +#include <asm/cputype.h> +#include <asm/cp15.h> +#include <asm/mcpm.h> + +#include "core.h" + +/* bits definition in SC_CPU_RESET_REQ[x]/SC_CPU_RESET_DREQ[x] +* 1 -- unreset; 0 -- reset +*/ +#define CORE_RESET_BIT (x) (1 << x) +#define NEON_RESET_BIT (x) (1 << (x + 4)) +#define CORE_DEBUG_RESET_BIT (x) (1 << (x + 9)) +#define CLUSTER_L2_RESET_BIT (1 << 8) +#define CLUSTER_DEBUG_RESET_BIT (1 << 13) + +/* +* bits definition in SC_CPU_RESET_STATUS[x] +* 1 -- reset status; 0 -- unreset status +*/ +#define CORE_RESET_STATUS (x) (1 << x) +#define NEON_RESET_STATUS (x) (1 << (x + 4)) +#define CORE_DEBUG_RESET_STATUS (x) (1 << (x + 9)) +#define CLUSTER_L2_RESET_STATUS (1 << 8) +#define CLUSTER_DEBUG_RESET_STATUS (1 << 13) +#define CORE_WFI_STATUS (x) (1 << (x + 16)) +#define CORE_WFE_STATUS (x) (1 << (x + 20)) +#define CORE_DEBUG_ACK (x) (1 << (x + 24)) + +#define SC_CPU_RESET_REQ (x) (0x520 + (x << 3))/* reset */ +#define SC_CPU_RESET_DREQ (x) (0x524 + (x << 3))/* unreset */ +#define SC_CPU_RESET_STATUS (x) (0x1520 + (x << 3)) + +#define FAB_SF_MODE 0x0c +#define FAB_SF_INVLD 0x10 + +/* bits definition in FB_SF_INVLD */ +#define FB_SF_INVLD_START (1 << 8) + +#define HIP04_MAX_CLUSTERS 4 +#define HIP04_MAX_CPUS_PER_CLUSTER 4 + +#define POLL_MSEC 10 +#define TIMEOUT_MSEC 1000 + +struct hip04_secondary_cpu_data { +u32 bootwrapper_phys; +u32 bootwrapper_size; +u32 bootwrapper_magic; +u32 relocation_entry; +u32 relocation_size; +}; + +static void __iomem *relocation, *sysctrl, *fabric; +static int hip04_cpu_table[HIP04_MAX_CLUSTERS ][HIP04_MAX_CPUS_PER_CLUSTER ]; +static DEFINE_SPINLOCK (boot_lock); +static struct hip04_secondary_cpu_data hip04_boot; + +static bool hip04_cluster_down (unsigned int cluster) +{ +int i; + +for (i =0 ; i <HIP04_MAX_CPUS_PER_CLUSTER ; i++) +if (hip04_cpu_table[cluster][i]) +return false; +return true; +} + +static void hip04_set_snoop_filter (unsigned int cluster,unsigned int on) +{ +unsigned long data; + +if (!fabric) +return ; + data =readl_relaxed (fabric +FAB_SF_MODE ); +if (on) + data |=1 << cluster; +else + data &= ~(1 << cluster); +writel_relaxed (data, fabric +FAB_SF_MODE ); +while (1 ) { +if (data ==readl_relaxed (fabric +FAB_SF_MODE )) +break ; + } +} +
arch/arm/mach-hisi/platmcpm.c line 108
Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10
-0+static int hip04_mcpm_power_up (unsigned int cpu,unsigned int cluster) +{ +unsigned long data, mask; + +if (!relocation || !sysctrl) +return -ENODEV ; +if (cluster >=HIP04_MAX_CLUSTERS || cpu >=HIP04_MAX_CPUS_PER_CLUSTER ) +return -EINVAL ; + +spin_lock (&boot_lock);
This is called in interruptible context. Surely you want spin_lock_irq() here.
Quoted 12 lines
arch/arm/mach-hisi/platmcpm.c new file +12
-0+writel_relaxed (hip04_boot.bootwrapper_phys, relocation); +writel_relaxed (hip04_boot.bootwrapper_magic, relocation +4 ); +writel_relaxed (virt_to_phys (mcpm_entry_point), relocation +8 ); +writel_relaxed (0 , relocation +12 ); + + if (hip04_cluster_down(cluster)) { + data = CLUSTER_L2_RESET_BIT | CLUSTER_DEBUG_RESET_BIT; + writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster)); + do { + mask = CLUSTER_L2_RESET_STATUS | \ + CLUSTER_DEBUG_RESET_STATUS; + data = readl_relaxed(sysctrl + \
arch/arm/mach-hisi/platmcpm.c line 130
Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10
-0+ SC_CPU_RESET_STATUS(cluster)); + }while (data & mask); +hip04_set_snoop_filter (cluster,1 ); + } + + hip04_cpu_table[cluster][cpu]++; + + data =CORE_RESET_BIT (cpu) |NEON_RESET_BIT (cpu) | \ +CORE_DEBUG_RESET_BIT (cpu); +writel_relaxed (data, sysctrl +SC_CPU_RESET_DREQ (cluster));
It might be a good idea to reset and initialize things only if hip04_cpu_table[cluster][cpu] was zero initially. Please see the comment in mcpm_cpu_power_down() discussing concurrent up/down operations, and the way races are handled using dcscb_use_count in dcscb_power_up() / dcscb_power_down() for example.
arch/arm/mach-hisi/platmcpm.c line 132
Quoted 2 lines
arch/arm/mach-hisi/platmcpm.c new file +2
-0+spin_unlock (&boot_lock); +msleep (POLL_MSEC );
You don't have to wait here. The MCPM up method should set things for the CPU to come up eventually and that CPU to signal itself when it is finally online.
Quoted 11 lines
arch/arm/mach-hisi/platmcpm.c new file +11
-0+return 0 ; +} + +static void hip04_mcpm_power_down (void ) +{ +unsigned int mpidr, cpu, cluster; +unsigned int v; + + mpidr =read_cpuid_mpidr (); + cpu =MPIDR_AFFINITY_LEVEL (mpidr,0 ); + cluster =MPIDR_AFFINITY_LEVEL (mpidr,1 );
arch/arm/mach-hisi/platmcpm.c line 154
Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10
-0+ +spin_lock (&boot_lock); +BUG_ON (__mcpm_cluster_state (cluster) !=CLUSTER_UP ); +__mcpm_cpu_going_down (cpu, cluster); + + hip04_cpu_table[cluster][cpu]--; +if (hip04_cpu_table[cluster][cpu]) { +pr_err ("Cluster %d CPU%d is still running\n" , cluster, cpu); + goto out; + }
This is wrong. Please see dcscb_power_down() or tc2_pm_down() for examples of how to deal with this situation.
arch/arm/mach-hisi/platmcpm.c line 156
Quoted 1 line
arch/arm/mach-hisi/platmcpm.c new file +1
-0+__mcpm_cpu_down (cpu, cluster);
That call should happen last i.e. after coherency has been disabled and the CPU is about to call WFI. Again, see the TC2 implementation for example. You may also read Documentation/arm/cluster-pm-race-avoidance.txt for more details about those calls and the algorithm behind them.
Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10
-0+spin_unlock (&boot_lock); + + asmvolatile ( +" mrc p15, 0, %0, c1, c0, 0\n" +" bic %0, %0, %1\n" +" mcr p15, 0, %0, c1, c0, 0\n" + :"=&r" (v) + :"Ir" (CR_C ) + :); +
arch/arm/mach-hisi/platmcpm.c line 176
Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10
-0+flush_cache_louis (); + + asmvolatile ( +/* Turn off coherency, disable SMP bit in ACTLR */ +" mrc p15, 0, %0, c1, c0, 1\n" +" bic %0, %0, %1\n" +" mcr p15, 0, %0, c1, c0, 1\n" + :"=&r" (v) + :"Ir" (0x40 ) + :);
The above code is not safe.
You should use v7_exit_coherency_flush() instead.
arch/arm/mach-hisi/platmcpm.c line 182
Quoted 5 lines
arch/arm/mach-hisi/platmcpm.c new file +5
-0+isb (); +dsb (); + +while (true) +wfi ();
This is wrong. By the time execution gets here, it is well possible that another CPU decided that this CPU should not be down anymore, in which case wfi() will return. See what's expected in this case by looking at mcpm_cpu_power_down() and what other backend implementations do.
Quoted 11 lines
arch/arm/mach-hisi/platmcpm.c new file +11
-0+return ; +out: +spin_unlock (&boot_lock); +} + +static int hip04_mcpm_wait_for_powerdown (unsigned int cpu,unsigned int cluster) +{ +unsigned int data, tries; + +BUG_ON (cluster >=HIP04_MAX_CLUSTERS || + cpu >=HIP04_MAX_CPUS_PER_CLUSTER );
arch/arm/mach-hisi/platmcpm.c line 203
Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10
-0+ +for (tries =0 ; tries <TIMEOUT_MSEC /POLL_MSEC ; tries++) { + data =readl_relaxed (sysctrl +SC_CPU_RESET_STATUS (cluster)); +if (!(data &CORE_WFI_STATUS (cpu))) { +msleep (POLL_MSEC ); +continue ; + } + data =CORE_RESET_BIT (cpu) |NEON_RESET_BIT (cpu) | \ +CORE_DEBUG_RESET_BIT (cpu); +writel_relaxed (data, sysctrl +SC_CPU_RESET_REQ (cluster));
Why are you resetting those here?
Quoted 134 lines
arch/arm/mach-hisi/platmcpm.c new file +131
-0+return 0 ; + } + +return -ETIMEDOUT ; +} + +static void hip04_mcpm_powered_up (void ) +{ +if (!relocation) +return ; +spin_lock (&boot_lock); +writel_relaxed (0 , relocation); +writel_relaxed (0 , relocation +4 ); +writel_relaxed (0 , relocation +8 ); +writel_relaxed (0 , relocation +12 ); +spin_unlock (&boot_lock); +} + +static const struct mcpm_platform_ops hip04_mcpm_ops = { + .power_up = hip04_mcpm_power_up, + .power_down = hip04_mcpm_power_down, + .wait_for_powerdown = hip04_mcpm_wait_for_powerdown, + .powered_up = hip04_mcpm_powered_up, +}; + +static bool __init hip04_cpu_table_init (void ) +{ +unsigned int mpidr, cpu, cluster; + + mpidr =read_cpuid_mpidr (); + cpu =MPIDR_AFFINITY_LEVEL (mpidr,0 ); + cluster =MPIDR_AFFINITY_LEVEL (mpidr,1 ); + +if (cluster >=HIP04_MAX_CLUSTERS || + cpu >=HIP04_MAX_CPUS_PER_CLUSTER ) { +pr_err ("%s: boot CPU is out of bound!\n" , __func__); +return false; + } +hip04_set_snoop_filter (cluster,1 ); + hip04_cpu_table[cluster][cpu] =1 ; +return true; +} + +static int __init hip04_mcpm_init (void ) +{ +struct device_node *np, *np_fab; +int ret = -ENODEV ; + + np =of_find_compatible_node (NULL ,NULL ,"hisilicon,sysctrl" ); +if (!np) + goto err; + np_fab =of_find_compatible_node (NULL ,NULL ,"hisilicon,hip04-fabric" ); +if (!np_fab) + goto err; + +if (of_property_read_u32 (np,"bootwrapper-phys" , + &hip04_boot.bootwrapper_phys)) { +pr_err ("failed to get bootwrapper-phys\n" ); + ret = -EINVAL ; + goto err; + } +if (of_property_read_u32 (np,"bootwrapper-size" , + &hip04_boot.bootwrapper_size)) { +pr_err ("failed to get bootwrapper-size\n" ); + ret = -EINVAL ; + goto err; + } +if (of_property_read_u32 (np,"bootwrapper-magic" , + &hip04_boot.bootwrapper_magic)) { +pr_err ("failed to get bootwrapper-magic\n" ); + ret = -EINVAL ; + goto err; + } +if (of_property_read_u32 (np,"relocation-entry" , + &hip04_boot.relocation_entry)) { +pr_err ("failed to get relocation-entry\n" ); + ret = -EINVAL ; + goto err; + } +if (of_property_read_u32 (np,"relocation-size" , + &hip04_boot.relocation_size)) { +pr_err ("failed to get relocation-size\n" ); + ret = -EINVAL ; + goto err; + } + + relocation =ioremap (hip04_boot.relocation_entry, + hip04_boot.relocation_size); +if (!relocation) { +pr_err ("failed to map relocation space\n" ); + ret = -ENOMEM ; + goto err; + } + sysctrl =of_iomap (np,0 ); +if (!sysctrl) { +pr_err ("failed to get sysctrl base\n" ); + ret = -ENOMEM ; + goto err_sysctrl; + } + fabric =of_iomap (np_fab,0 ); +if (!fabric) { +pr_err ("failed to get fabric base\n" ); + ret = -ENOMEM ; + goto err_fabric; + } + +memblock_reserve (hip04_boot.bootwrapper_phys, + hip04_boot.bootwrapper_size); + +if (!hip04_cpu_table_init ()) +return -EINVAL ; + ret =mcpm_platform_register (&hip04_mcpm_ops); +if (!ret) { +mcpm_sync_init (NULL ); +pr_info ("HiP04 MCPM initialized\n" ); + } +return ret; +err_fabric: +iounmap (sysctrl); +err_sysctrl: +iounmap (relocation); +err: +return ret; +} +early_initcall (hip04_mcpm_init); + +bool __init hip04_smp_init_ops (void ) +{ +mcpm_smp_set_ops (); +return true; +}Signature · 1 line
1.8.3.2
PATCH v3 7/13 ARM: hisi: add hip04 SoC support
Quoted 7 lines · Nicolas Pitre
arch/arm/mach-hisi/platmcpm.c line 130
Quoted 4 lines · Haojian Zhuang
arch/arm/mach-hisi/platmcpm.c new file +4
-0+ + data =CORE_RESET_BIT (cpu) |NEON_RESET_BIT (cpu) | \ +CORE_DEBUG_RESET_BIT (cpu); +writel_relaxed (data, sysctrl +SC_CPU_RESET_DREQ (cluster));
Quoted 6 lines
It might be a good idea to reset and initialize things only if hip04_cpu_table[cluster][cpu] was zero initially. Please see the comment in
mcpm_cpu_power_down()discussing concurrent up/down operations, and the way races are handled usingdcscb_use_countindcscb_power_up()/dcscb_power_down()for example.
I'll use it as reference.
Quoted 7 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ spin_unlock(&boot_lock); + msleep(POLL_MSEC);You don't have to wait here. The MCPM up method should set things for the CPU to come up eventually and that CPU to signal itself when it is finally online.
I have to wait. Otherwise, I'll meet hang when make the CPU offline & online continuously.
Quoted 56 lines
Quoted 11 lines
arch/arm/mach-hisi/platmcpm.c new file +11
-0+return 0 ; +} + +static void hip04_mcpm_power_down (void ) +{ +unsigned int mpidr, cpu, cluster; +unsigned int v; + + mpidr =read_cpuid_mpidr (); + cpu =MPIDR_AFFINITY_LEVEL (mpidr,0 ); + cluster =MPIDR_AFFINITY_LEVEL (mpidr,1 );arch/arm/mach-hisi/platmcpm.c line 154
Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10
-0+ +spin_lock (&boot_lock); +BUG_ON (__mcpm_cluster_state (cluster) !=CLUSTER_UP ); +__mcpm_cpu_going_down (cpu, cluster); + + hip04_cpu_table[cluster][cpu]--; +if (hip04_cpu_table[cluster][cpu]) { +pr_err ("Cluster %d CPU%d is still running\n" , cluster, cpu); + goto out; + }This is wrong. Please see
dcscb_power_down()ortc2_pm_down()for examples of how to deal with this situation.Quoted 1 line
+
__mcpm_cpu_down(cpu, cluster);That call should happen last i.e. after coherency has been disabled and the CPU is about to call WFI. Again, see the TC2 implementation for example. You may also read
Documentation/arm/cluster-pm-race-avoidance.txtfor more details about those calls and the algorithm behind them.Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10
-0+spin_unlock (&boot_lock); + + asmvolatile ( +" mrc p15, 0, %0, c1, c0, 0\n" +" bic %0, %0, %1\n" +" mcr p15, 0, %0, c1, c0, 0\n" + :"=&r" (v) + :"Ir" (CR_C ) + :); +arch/arm/mach-hisi/platmcpm.c line 176
Quoted 10 lines
arch/arm/mach-hisi/platmcpm.c new file +10
-0+flush_cache_louis (); + + asmvolatile ( +/* Turn off coherency, disable SMP bit in ACTLR */ +" mrc p15, 0, %0, c1, c0, 1\n" +" bic %0, %0, %1\n" +" mcr p15, 0, %0, c1, c0, 1\n" + :"=&r" (v) + :"Ir" (0x40 ) + :);The above code is not safe.
Quoted 2 lines
You should use
v7_exit_coherency_flush()instead.
OK.
Quoted 27 lines
arch/arm/mach-hisi/platmcpm.c line 182
Quoted 5 lines
arch/arm/mach-hisi/platmcpm.c new file +5
-0+isb (); +dsb (); + +while (true) +wfi ();This is wrong. By the time execution gets here, it is well possible that another CPU decided that this CPU should not be down anymore, in which case
wfi()will return. See what's expected in this case by looking atmcpm_cpu_power_down()and what other backend implementations do.Quoted 15 lines
arch/arm/mach-hisi/platmcpm.c new file +15
-0+return ; +out: +spin_unlock (&boot_lock); +} + +static int hip04_mcpm_wait_for_powerdown (unsigned int cpu,unsigned int cluster) +{ +unsigned int data, tries; + +BUG_ON (cluster >=HIP04_MAX_CLUSTERS || + cpu >=HIP04_MAX_CPUS_PER_CLUSTER ); + +for (tries =0 ; tries <TIMEOUT_MSEC /POLL_MSEC ; tries++) { + data =readl_relaxed (sysctrl +SC_CPU_RESET_STATUS (cluster)); +if (!(data &CORE_WFI_STATUS (cpu))) {
Quoted 9 lines
arch/arm/mach-hisi/platmcpm.c line 203
Quoted 6 lines
arch/arm/mach-hisi/platmcpm.c new file +6
-0+msleep (POLL_MSEC ); +continue ; + } + data =CORE_RESET_BIT (cpu) |NEON_RESET_BIT (cpu) | \ +CORE_DEBUG_RESET_BIT (cpu); +writel_relaxed (data, sysctrl +SC_CPU_RESET_REQ (cluster));Why are you resetting those here?
Do you mean that I should move this reset code into hip04_mcpm_power_down()?
Regards
Haojian
PATCH v3 8/13 ARM: dts: add hip04-d01 dts file
In reply to Haojian ZhuangAdd hip04.dtsi & hip04-d01.dts file to support HiP04 SoC platform.
--- Documentation/devicetree/bindings/arm/gic.txt | 1 + .../bindings/arm/hisilicon/hisilicon.txt | 10 + .../devicetree/bindings/clock/hip04-clock.txt | 20 ++ arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/hip04-d01.dts | 74 +++++++ arch/arm/boot/dts/hip04.dtsi | 239 +++++++++++++++++++++ 6 files changed, 345 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/hip04-clock.txt create mode 100644 arch/arm/boot/dts/hip04-d01.dts create mode 100644 arch/arm/boot/dts/hip04.dtsi
Documentation/devicetree/bindings/arm/gic.txt +1 -0
@@ -16,6 +16,7 @@ Main node required properties: "arm,cortex-a9-gic" "arm,cortex-a7-gic" "arm,arm11mp-gic" + "hisilicon,hip04-gic" - interrupt-controller : Identifies the node as an interrupt controller - #interrupt-cells : Specifies the number of cells needed to encode an interrupt source. The type shall be a <u32> and the value shall be 3.
Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt +10 -0
@@ -4,6 +4,10 @@ Hisilicon Platforms Device Tree Bindings Hi4511 Board Required root node properties: - compatible = "hisilicon,hi3620-hi4511"; +HiP04 D01 Board +Required root node properties: + - compatible = "hisilicon,hip04-d01"; + Hisilicon system controller
@@ -19,6 +23,11 @@ Optional properties: If reg value is not zero, cpun exit wfi and go - resume-offset : offset in sysctrl for notifying cpu0 when resume - reboot-offset : offset in sysctrl for system reboot +- relocation-entry : relocation address of secondary cpu boot code +- relocation-size : relocation size of secondary cpu boot code +- bootwrapper-phys : physical address of boot wrapper +- bootwrapper-size : size of boot wrapper +- bootwrapper-magic : magic number for secondary cpu in boot wrapper Example:
@@ -31,6 +40,7 @@ Example: reboot-offset = <0x4>; }; + PCTRL: Peripheral misc control register Required Properties:
Documentation/devicetree/bindings/clock/hip04-clock.txt new file +20 -0
@@ -0,0 +1,20 @@ +* Hisilicon HiP04 Clock Controller + +The HiP04 clock controller generates and supplies clock to various +controllers within the HiP04 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "hisilicon,hip04-clock" - controller compatible with HiP04 SoC. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in <dt-bindings/clock/hip04-clock.h>.
arch/arm/boot/dts/Makefile +1 -0
@@ -80,6 +80,7 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \ dtb-$(CONFIG_ARCH_HI3xxx) += hi3620-hi4511.dtb dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \ ecx-2000.dtb +dtb-$(CONFIG_ARCH_HIP04) += hip04-d01.dtb dtb-$(CONFIG_ARCH_INTEGRATOR) += integratorap.dtb \ integratorcp.dtb dtb-$(CONFIG_ARCH_KEYSTONE) += k2hk-evm.dtb \
arch/arm/boot/dts/hip04-d01.dts new file +74 -0
74 lines not on this page · raw message
arch/arm/boot/dts/hip04.dtsi new file +239 -0
239 lines not on this page · raw message
Signature · 1 line
1.8.3.2
PATCH v3 9/13 ARM: config: append hip04_defconfig
In reply to Haojian ZhuangSelect HiP04 SoC configuration by hip04_defconfig.
--- arch/arm/configs/hip04_defconfig | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 arch/arm/configs/hip04_defconfig
arch/arm/configs/hip04_defconfig new file +74 -0
@@ -0,0 +1,74 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_RD_GZIP=y +# CONFIG_ARCH_MULTI_V6 is not set +# CONFIG_ARCH_MULTI_V7 is not set +CONFIG_ARCH_MULTI_V7_LPAE=y +CONFIG_ARCH_HISI=y +CONFIG_ARCH_HIP04=y +CONFIG_SMP=y +CONFIG_NR_CPUS=16 +CONFIG_MCPM=y +CONFIG_MCPM_QUAD_CLUSTER=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y +CONFIG_HIGHMEM=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_NET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_SD=y +CONFIG_ATA=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_NETDEVICES=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_REGULATOR_GPIO=y +CONFIG_DRM=y +CONFIG_FB_SIMPLE=y +CONFIG_RTC_CLASS=y +CONFIG_EXT4_FS=y +CONFIG_TMPFS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_UART_8250=y +CONFIG_EARLY_PRINTK=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_DEBUG_USER=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=y +CONFIG_KVM_ARM_HOST=y +CONFIG_KVM_ARM_MAX_VCPUS=4 +CONFIG_KVM_ARM_VGIC=y
Signature · 1 line
1.8.3.2
PATCH v3 10/13 ARM: config: select ARCH_HISI in hi3xxx_defconfig
In reply to Haojian ZhuangSince ARCH_HISI is added as common configuration of both ARCH_HI3xxx and ARCH_HIP04, update it into hi3xxx_defconfig.
--- arch/arm/configs/hi3xxx_defconfig | 1 + 1 file changed, 1 insertion(+)
arch/arm/configs/hi3xxx_defconfig +1 -0
@@ -3,6 +3,7 @@ CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BLK_DEV_INITRD=y CONFIG_RD_LZMA=y +CONFIG_ARCH_HISI=y CONFIG_ARCH_HI3xxx=y CONFIG_SMP=y CONFIG_PREEMPT=y
Signature · 1 line
1.8.3.2
PATCH v3 11/13 ARM: hisi: enable erratum 798181 of A15 on HiP04
In reply to Haojian ZhuangFrom: Kefeng Wang <[email protected]>
The commit 93dc688 (ARM: 7684/1: errata: Workaround for Cortex-A15 erratum 798181 (TLBI/DSB operations)) introduced a workaround for Cortex-A15 erratum 798181. Enable it for HIP04(Cortex-a15 r3p2).
--- arch/arm/mach-hisi/Kconfig | 1 + 1 file changed, 1 insertion(+)
arch/arm/mach-hisi/Kconfig +1 -0
@@ -21,6 +21,7 @@ config ARCH_HI3xxx config ARCH_HIP04 bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7_LPAE + select ARM_ERRATA_798181 if SMP select HAVE_ARM_ARCH_TIMER select MCPM if SMP help
Signature · 1 line
1.8.3.2
PATCH v3 12/13 ARM: dts: Add PMU support in HiP04
In reply to Haojian ZhuangFrom: Kefeng Wang <[email protected]>
ARM Performance Monitor Units are available on the HiP04. So add the support in the dtsi.
Simply tested with perf.
--- arch/arm/boot/dts/hip04.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/arm/boot/dts/hip04.dtsi +20 -0
@@ -218,6 +218,26 @@ status = "ok"; }; + arm-pmu { + compatible = "arm,cortex-a15-pmu"; + interrupts = <0 64 4>, + <0 65 4>, + <0 66 4>, + <0 67 4>, + <0 68 4>, + <0 69 4>, + <0 70 4>, + <0 71 4>, + <0 72 4>, + <0 73 4>, + <0 74 4>, + <0 75 4>, + <0 76 4>, + <0 77 4>, + <0 78 4>, + <0 79 4>; + }; + timer { compatible = "arm,armv7-timer"; interrupts = <1 13 0xf08>,
Signature · 1 line
1.8.3.2
PATCH v3 13/13 virt: arm: support hip04 gic
In reply to Haojian ZhuangIn HiP04 SoC, the address of GICH_APR & GICH_LR0 registers are different from ARM standard SoC. So add the support of HiP04 SoC in VGIC.
--- arch/arm/kvm/interrupts_head.S | 23 +++++++++++++++++++---- include/linux/irqchip/arm-gic.h | 3 +++ virt/kvm/arm/vgic.c | 10 ++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-)
arch/arm/kvm/interrupts_head.S +19 -4
@@ -419,7 +419,9 @@ vcpu .req r0 @ vcpu pointer always in r0 ldr r7, [r2, #GICH_EISR1] ldr r8, [r2, #GICH_ELRSR0] ldr r9, [r2, #GICH_ELRSR1] - ldr r10, [r2, #GICH_APR] + ldr r10, =gich_apr + ldr r10, [r10] + ldr r10, [r2, r10] str r3, [r11, #VGIC_CPU_HCR] str r4, [r11, #VGIC_CPU_VMCR]
@@ -435,7 +437,9 @@ vcpu .req r0 @ vcpu pointer always in r0 str r5, [r2, #GICH_HCR] /* Save list registers */ - add r2, r2, #GICH_LR0 + ldr r10, =gich_lr0 + ldr r10, [r10] + add r2, r2, r10 add r3, r11, #VGIC_CPU_LR ldr r4, [r11, #VGIC_CPU_NR_LR] 1: ldr r6, [r2], #4
@@ -469,10 +473,14 @@ vcpu .req r0 @ vcpu pointer always in r0 str r3, [r2, #GICH_HCR] str r4, [r2, #GICH_VMCR] - str r8, [r2, #GICH_APR] + ldr r6, =gich_apr + ldr r6, [r6] + str r8, [r2, r6] /* Restore list registers */ - add r2, r2, #GICH_LR0 + ldr r6, =gich_lr0 + ldr r6, [r6] + add r2, r2, r6 add r3, r11, #VGIC_CPU_LR ldr r4, [r11, #VGIC_CPU_NR_LR] 1: ldr r6, [r3], #4
@@ -618,3 +626,10 @@ vcpu .req r0 @ vcpu pointer always in r0 .macro load_vcpu mrc p15, 4, vcpu, c13, c0, 2 @ HTPIDR .endm + + .global gich_apr +gich_apr: + .long GICH_APR + .global gich_lr0 +gich_lr0: + .long GICH_LR0
include/linux/irqchip/arm-gic.h +3 -0
@@ -49,6 +49,8 @@#define GICH_ELRSR1 0x34#define GICH_APR 0xf0#define GICH_LR0 0x100 +#define HIP04_GICH_APR 0x70 +#define HIP04_GICH_LR0 0x80#define GICH_HCR_EN (1 << 0)#define GICH_HCR_UIE (1 << 1)
@@ -78,6 +80,7 @@struct device_node ;extern struct irq_chip gic_arch_extn; +extern unsigned int gich_apr, gich_lr0;void gic_init_bases (unsigned int ,int ,void __iomem *,void __iomem *,u32 offset,struct device_node *);
virt/kvm/arm/vgic.c +8 -2
@@ -1478,8 +1478,14 @@ int kvm_vgic_hyp_init(void) vgic_node =of_find_compatible_node (NULL ,NULL ,"arm,cortex-a15-gic" );if (!vgic_node) { -kvm_err ("error: no compatible vgic node in DT\n" ); -return -ENODEV ; + vgic_node =of_find_compatible_node (NULL ,NULL , +"hisilicon,hip04-gic" ); +if (!vgic_node) { +kvm_err ("error: no compatible vgic node in DT\n" ); +return -ENODEV ; + } + gich_apr =HIP04_GICH_APR ; + gich_lr0 =HIP04_GICH_LR0 ; } vgic_maint_irq =irq_of_parse_and_map (vgic_node,0 );
Signature · 1 line
1.8.3.2
PATCH v3 13/13 virt: arm: support hip04 gic
Quoted 2 lines · Haojian Zhuang
In HiP04 SoC, the address of
GICH_APR&GICH_LR0registers are different from ARM standard SoC. So add the support of HiP04 SoC in VGIC.
Please explain the differences in the commit message.
Quoted 40 lines
Signed-off-by Haojian Zhuang <[email protected]>--- arch/arm/kvm/interrupts_head.S | 23 +++++++++++++++++++---- include/linux/irqchip/arm-gic.h | 3 +++ virt/kvm/arm/vgic.c | 10 ++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-)arch/arm/kvm/interrupts_head.S +8
-3@@ -419,7 +419,9 @@ vcpu .req r0 @ vcpu pointer always in r0 ldr r7, [r2, #GICH_EISR1] ldr r8, [r2, #GICH_ELRSR0] ldr r9, [r2, #GICH_ELRSR1] - ldr r10, [r2, #GICH_APR] + ldr r10, =gich_apr + ldr r10, [r10] + ldr r10, [r2, r10] str r3, [r11, #VGIC_CPU_HCR] str r4, [r11, #VGIC_CPU_VMCR]@@ -435,7 +437,9 @@ vcpu .req r0 @ vcpu pointer always in r0 str r5, [r2, #GICH_HCR] /* Save list registers */ - add r2, r2, #GICH_LR0 + ldr r10, =gich_lr0 + ldr r10, [r10] + add r2, r2, r10 add r3, r11, #VGIC_CPU_LR ldr r4, [r11, #VGIC_CPU_NR_LR] 1: ldr r6, [r2], #4@@ -469,10 +473,14 @@ vcpu .req r0 @ vcpu pointer always in r0 str r3, [r2, #GICH_HCR] str r4, [r2, #GICH_VMCR] - str r8, [r2, #GICH_APR] + ldr r6, =gich_apr + ldr r6, [r6]
arch/arm/kvm/interrupts_head.S vcpu .req r0 @ vcpu pointer always in r0 · line 486
Quoted 10 lines
arch/arm/kvm/interrupts_head.S +4
-1+ str r8, [r2, r6] /* Restore list registers */ - add r2, r2, #GICH_LR0 + ldr r6, =gich_lr0 + ldr r6, [r6] + add r2, r2, r6 add r3, r11, #VGIC_CPU_LR ldr r4, [r11, #VGIC_CPU_NR_LR] 1: ldr r6, [r3], #4
So we get four extra memory accesses per world switch, just to find out about the new fancy memory map. Let's just say that I'm not exactly pleased.
How about encoding that in the field containing the number of LRs? the distance between GICH_APR and GICH_LR0 is constant (0x10), so we only need to encode the offset of GICH_APR. This way, we only have to read one single word from memory. Not pretty, but I'm not really willing to impact
Quoted 40 lines
arch/arm/kvm/interrupts_head.S +7
-0@@ -618,3 +626,10 @@ vcpu .req r0 @ vcpu pointer always in r0 .macro load_vcpu mrc p15, 4, vcpu, c13, c0, 2 @ HTPIDR .endm + + .global gich_apr +gich_apr: + .long GICH_APR + .global gich_lr0 +gich_lr0: + .long GICH_LR0include/linux/irqchip/arm-gic.h +3
-0@@ -49,6 +49,8 @@#define GICH_ELRSR1 0x34#define GICH_APR 0xf0#define GICH_LR0 0x100 +#define HIP04_GICH_APR 0x70 +#define HIP04_GICH_LR0 0x80#define GICH_HCR_EN (1 << 0)#define GICH_HCR_UIE (1 << 1)@@ -78,6 +80,7 @@struct device_node ;extern struct irq_chip gic_arch_extn; +extern unsigned int gich_apr, gich_lr0;void gic_init_bases (unsigned int ,int ,void __iomem *,void __iomem *,u32 offset,struct device_node *);virt/kvm/arm/vgic.c +0
-0@@ -1478,8 +1478,14 @@ int kvm_vgic_hyp_init(void) vgic_node =of_find_compatible_node (NULL ,NULL ,"arm,cortex-a15-gic" );if (!vgic_node) {
virt/kvm/arm/vgic.c int kvm_vgic_hyp_init(void) · line 1488
Quoted 10 lines
virt/kvm/arm/vgic.c +8
-2-kvm_err ("error: no compatible vgic node in DT\n" ); -return -ENODEV ; + vgic_node =of_find_compatible_node (NULL ,NULL , +"hisilicon,hip04-gic" ); +if (!vgic_node) { +kvm_err ("error: no compatible vgic node in DT\n" ); +return -ENODEV ; + } + gich_apr =HIP04_GICH_APR ; + gich_lr0 =HIP04_GICH_LR0 ;
Consider using of_find_matching_node_and_match instead, with a set of flags for this particular case.
virt/kvm/arm/vgic.c int kvm_vgic_hyp_init(void) · line 1491
Quoted 3 lines
virt/kvm/arm/vgic.c +0
-0} vgic_maint_irq =irq_of_parse_and_map (vgic_node,0 );
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny.
PATCH v3 13/13 virt: arm: support hip04 gic
Quoted 6 lines · Marc Zyngier
Quoted 2 lines · Haojian Zhuang
In HiP04 SoC, the address of
GICH_APR&GICH_LR0registers are different from ARM standard SoC. So add the support of HiP04 SoC in VGIC.Please explain the differences in the commit message.
OK. I'll append it.
Quoted 55 lines
Quoted 40 lines
Signed-off-by Haojian Zhuang <[email protected]>--- arch/arm/kvm/interrupts_head.S | 23 +++++++++++++++++++---- include/linux/irqchip/arm-gic.h | 3 +++ virt/kvm/arm/vgic.c | 10 ++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-)arch/arm/kvm/interrupts_head.S +8
-3@@ -419,7 +419,9 @@ vcpu .req r0 @ vcpu pointer always in r0 ldr r7, [r2, #GICH_EISR1] ldr r8, [r2, #GICH_ELRSR0] ldr r9, [r2, #GICH_ELRSR1] - ldr r10, [r2, #GICH_APR] + ldr r10, =gich_apr + ldr r10, [r10] + ldr r10, [r2, r10] str r3, [r11, #VGIC_CPU_HCR] str r4, [r11, #VGIC_CPU_VMCR]@@ -435,7 +437,9 @@ vcpu .req r0 @ vcpu pointer always in r0 str r5, [r2, #GICH_HCR] /* Save list registers */ - add r2, r2, #GICH_LR0 + ldr r10, =gich_lr0 + ldr r10, [r10] + add r2, r2, r10 add r3, r11, #VGIC_CPU_LR ldr r4, [r11, #VGIC_CPU_NR_LR] 1: ldr r6, [r2], #4@@ -469,10 +473,14 @@ vcpu .req r0 @ vcpu pointer always in r0 str r3, [r2, #GICH_HCR] str r4, [r2, #GICH_VMCR] - str r8, [r2, #GICH_APR] + ldr r6, =gich_apr + ldr r6, [r6]arch/arm/kvm/interrupts_head.S vcpu .req r0 @ vcpu pointer always in r0 · line 486
Quoted 10 lines
arch/arm/kvm/interrupts_head.S +4
-1+ str r8, [r2, r6] /* Restore list registers */ - add r2, r2, #GICH_LR0 + ldr r6, =gich_lr0 + ldr r6, [r6] + add r2, r2, r6 add r3, r11, #VGIC_CPU_LR ldr r4, [r11, #VGIC_CPU_NR_LR] 1: ldr r6, [r3], #4So we get four extra memory accesses per world switch, just to find out about the new fancy memory map. Let's just say that I'm not exactly pleased.
Quoted 6 lines
How about encoding that in the field containing the number of LRs? the distance between
GICH_APRandGICH_LR0is constant (0x10), so we only need to encode the offset ofGICH_APR. This way, we only have to read one single word from memory. Not pretty, but I'm not really willing to impact
Yes, it's better.
Quoted 39 lines
Quoted 39 lines
arch/arm/kvm/interrupts_head.S +7
-0@@ -618,3 +626,10 @@ vcpu .req r0 @ vcpu pointer always in r0 .macro load_vcpu mrc p15, 4, vcpu, c13, c0, 2 @ HTPIDR .endm + + .global gich_apr +gich_apr: + .long GICH_APR + .global gich_lr0 +gich_lr0: + .long GICH_LR0include/linux/irqchip/arm-gic.h +3
-0@@ -49,6 +49,8 @@#define GICH_ELRSR1 0x34#define GICH_APR 0xf0#define GICH_LR0 0x100 +#define HIP04_GICH_APR 0x70 +#define HIP04_GICH_LR0 0x80#define GICH_HCR_EN (1 << 0)#define GICH_HCR_UIE (1 << 1)@@ -78,6 +80,7 @@struct device_node ;extern struct irq_chip gic_arch_extn; +extern unsigned int gich_apr, gich_lr0;void gic_init_bases (unsigned int ,int ,void __iomem *,void __iomem *,u32 offset,struct device_node *);virt/kvm/arm/vgic.c +0
-0@@ -1478,8 +1478,14 @@ int kvm_vgic_hyp_init(void)
Quoted 16 lines
virt/kvm/arm/vgic.c int kvm_vgic_hyp_init(void) · line 1488
Quoted 12 lines
virt/kvm/arm/vgic.c +8
-2vgic_node =of_find_compatible_node (NULL ,NULL ,"arm,cortex-a15-gic" );if (!vgic_node) { -kvm_err ("error: no compatible vgic node in DT\n" ); -return -ENODEV ; + vgic_node =of_find_compatible_node (NULL ,NULL , +"hisilicon,hip04-gic" ); +if (!vgic_node) { +kvm_err ("error: no compatible vgic node in DT\n" ); +return -ENODEV ; + } + gich_apr =HIP04_GICH_APR ; + gich_lr0 =HIP04_GICH_LR0 ;Consider using
of_find_matching_node_and_matchinstead, with a set of flags for this particular case.
OK. I'll use it.
Thanks
Haojian