Skip to contentSkip to conversation

enable Hisilicon HiP04 SoC

PATCH Superseded Haojian Zhuang 4 participants 26 messages Apr 18, 2014 – Apr 25, 2014

Subsystems (17)

v3 of 17 Superseded Latest is v17 →

lore
Share & tools
lore
#0 lore raw

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
#1 lore raw

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
index 4a2fc0b..5a311af 100644
@@ -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
#2 lore raw

PATCH v3 2/13 ARM: append ARCH_MULTI_V7_LPAE

In reply to Haojian Zhuang

Add 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
index ab438cb..9a2214e 100644
@@ -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
index b0cb072..be0512d 100644
@@ -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
index 830b76e..9b6b3f8 100644
@@ -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
index 3f73eec..16f69ae 100644
@@ -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
index cb31d43..1958791 100644
@@ -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
index a028be2..0da77d2 100644
@@ -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
index 0f92ba8..c2a1fce 100644
@@ -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
index 92d660f..12e1b49 100644
@@ -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
index 657d52d..a1d69d1 100644
@@ -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
#3 lore raw

PATCH v3 2/13 ARM: append ARCH_MULTI_V7_LPAE

Hi Haojian,

Quoted 23 lines · Haojian Zhuang

Add 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 +0 -0
index ab438cb..9a2214e 100644

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 -0
 	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)"

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_L2X0
arch/arm/mach-berlin/Kconfig +1 -1
index b0cb072..be0512d 100644
@@ -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
index 830b76e..9b6b3f8 100644
@@ -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 +1 -1
index 3f73eec..16f69ae 100644
@@ -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 -1
 	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

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
#4 lore raw

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_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 +0 -0
index ab438cb..9a2214e 100644

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

Quoted 5 lines
arch/arm/Kconfig +0 -0
      default 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 -1
 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/Kconfig config MACH_ARMADA_38X · line 65

Quoted 12 lines
arch/arm/Kconfig +1 -1
      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

Thanks,

Gregory

--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

#5 lore raw

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_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 +0 -0
index ab438cb..9a2214e 100644

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

Quoted 5 lines
arch/arm/Kconfig +0 -0
      default 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 -1
 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/Kconfig config MACH_ARMADA_38X · line 65

Quoted 12 lines
arch/arm/Kconfig +1 -1
      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

Thanks,

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
#6 lore raw

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_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 +0 -0
index ab438cb..9a2214e 100644

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 -0
      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)"

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_LPAE vs ARCH_MULTI_V7 si 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

#7 lore raw

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_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 +0 -0
index ab438cb..9a2214e 100644

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

Quoted 5 lines
arch/arm/Kconfig +0 -0
      default 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.

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_LPAE as the precondition on ARMADA_XP. I'll keep ARCH_MULTI_V7 as the precondition on other armada chips in mach-berlin directory.

In mach-mvebu actually

Quoted 3 lines

So when multi_v7_lpae_defconfig is appended, only ARMADA_XP is 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
#8 lore raw

PATCH v3 3/13 ARM: hisi: add ARCH_HISI

In reply to Haojian Zhuang

Since 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
index 41c1931..4c2798a 100644
@@ -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
index feee4db..da16efd 100644
@@ -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
#9 lore raw

PATCH v3 4/13 irq: gic: use mask field in GICC_IAR

In reply to Haojian Zhuang

Bit[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
index 4300b66..8fd27bf 100644
@@ -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
index 7ed92d0..55933aa 100644
@@ -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
#10 lore raw

PATCH v3 5/13 irq: gic: support hip04 gic

In reply to 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, 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
index 8fd27bf..18f3d56 100644
@@ -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
#11 lore raw

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_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 +0 -0
index 8fd27bf..18f3d56 100644

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 -0
        raw_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 -1
                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")) {

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.
#12 lore raw

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_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(-)
Quoted 12 lines

drivers/irqchip/irq-gic.c struct gic_chip_data { · line 72

Quoted 10 lines
drivers/irqchip/irq-gic.c +2 -0
index 8fd27bf..18f3d56 100644
@@ -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   32

What 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_data pointer, 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 -0
        raw_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 -1
                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);
        }
 
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.

#13 lore raw

PATCH v3 6/13 ARM: mcpm: support 4 clusters in HiP04

In reply to 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.

---
 arch/arm/Kconfig            | 8 ++++++++
 arch/arm/include/asm/mcpm.h | 5 +++++
 2 files changed, 13 insertions(+)
arch/arm/Kconfig +8 -0
index 9a2214e..f2a25be 100644
@@ -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
index 608516e..fc8d70d 100644
@@ -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
#14 lore raw

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

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
index 9a2214e..f2a25be 100644

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 -0
 config BIG_LITTLE
 	bool "big.LITTLE support (Experimental)"
 	depends on CPU_V7 && SMP
arch/arm/include/asm/mcpm.h +5 -0
index 608516e..fc8d70d 100644
@@ -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
#15 lore raw

PATCH v3 7/13 ARM: hisi: add hip04 SoC support

In reply to 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.

---
 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
index f2a25be..2961627 100644
@@ -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
index da16efd..0bfd739 100644
@@ -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
index 2ae1b59..e7a8640 100644
@@ -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
index af23ec2..1e60795 100644
@@ -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
index 741faf3..6489e57 100644
@@ -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
#16 lore raw

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.

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.c
arch/arm/Kconfig +1 -1
index f2a25be..2961627 100644
@@ -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 +0 -0
index da16efd..0bfd739 100644

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
new file mode 100644
index 0000000..4ac8d4b
@@ -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);
+
+	asm volatile(
+	"	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();
+
+	asm volatile(
+	/* 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
#17 lore raw

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 using dcscb_use_count in dcscb_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() or tc2_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.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);
+
+     asm volatile(
+     "       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();
+
+     asm volatile(
+     /* 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 at mcpm_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

#18 lore raw

PATCH v3 8/13 ARM: dts: add hip04-d01 dts file

In reply to Haojian Zhuang

Add 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
index 5573c08..150f7d6 100644
@@ -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
index df0a452..4681f15 100644
@@ -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
new file mode 100644
index 0000000..4d31ae3
@@ -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
index 35c146f..7119bca 100644
@@ -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
#19 lore raw

PATCH v3 9/13 ARM: config: append hip04_defconfig

In reply to Haojian Zhuang

Select 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
new file mode 100644
index 0000000..3e674f7
@@ -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
#20 lore raw

PATCH v3 10/13 ARM: config: select ARCH_HISI in hi3xxx_defconfig

In reply to Haojian Zhuang

Since 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
index f186bdf..f8c78ac 100644
@@ -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
#21 lore raw

PATCH v3 11/13 ARM: hisi: enable erratum 798181 of A15 on HiP04

In reply to Haojian Zhuang

From: 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
index 0bfd739..82e85717 100644
@@ -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
#22 lore raw

PATCH v3 12/13 ARM: dts: Add PMU support in HiP04

In reply to Haojian Zhuang

From: 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
index 7e909ee..98aa9fd 100644
@@ -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
#23 lore raw

PATCH v3 13/13 virt: arm: support hip04 gic

In reply to Haojian Zhuang

In 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
index 76af9302..13e4144 100644
@@ -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
index 55933aa..653525b 100644
@@ -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
index 47b2983..010e491 100644
@@ -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
#24 lore raw

PATCH v3 13/13 virt: arm: support hip04 gic

Quoted 2 lines · Haojian Zhuang

In 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.

Please explain the differences in the commit message.

Quoted 40 lines
---
 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
index 76af9302..13e4144 100644
@@ -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_LR0
include/linux/irqchip/arm-gic.h +3 -0
index 55933aa..653525b 100644
@@ -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
index 47b2983..010e491 100644
@@ -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.
#25 lore raw

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_LR0 registers 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
---
 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
index 76af9302..13e4144 100644
@@ -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.

Quoted 6 lines

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

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_LR0
include/linux/irqchip/arm-gic.h +3 -0
index 55933aa..653525b 100644
@@ -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
index 47b2983..010e491 100644
@@ -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 -2
      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;

Consider using of_find_matching_node_and_match instead, with a set of flags for this particular case.

OK. I'll use it.

Thanks
Haojian