All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/17] Add System Error Interrupt support to Armada SoCs
@ 2018-04-21 13:55 ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

The ICU is an IRQ chip found in Armada CP110. It currently has 207 wired
inputs. Its purpose is to aggregate all CP interrupts and report them to
the AP through MSIs. The ICU writes into GIC registers (AP side) by way
of the interconnect. These interrupts can be of several groups:
- SecuRe (SR);
- Non-SecuRe (NSR);
- System Error Interrupts (SEI);
- RAM Error Interrupts (REI);
- ...
Each ICU wired interrupt can be of any of these groups. The group is
encoded in the MSI payload.

Until now, only the non-secure interrupts (NSR) were handled by the ICU
driver. Interrupts of another group could work by chance because the
ICU driver does not erase all ATF configuration; it only erases the
configuration for NSR interrupts.

This series aims at adding support for the System Error Interrupts
(SEI). For this purpose, the ICU driver is a bit reworked to separate
the ICU 'generic' configuration from the NSR-related handling. Then,
the SEI driver (part of the GIC) is introduced and finally, support for
SEI interrupts are also added to the ICU driver.

The SEI driver is a bit different than its cousin the GICP because it
must handle MSIs from the CPs, as well as wired interrupts from the AP
itself. MSIs and wired interrupts will automatically update two
registers (GICP_SECR0/GICP_SECR1) that will trigger a single top-level
interrupt (SPI #32).

As this is my first contribution in the IRQ subsystem I might have
missed some specificities or misunderstood the API, please do not
hesitate to correct me if I'm wrong.

Also, for the sake of understandability (and because I love ASCII art),
this is a try to explain the ICU/SEI architecture:


 ---------------------------------------------------------------------
/                                                                      \
|                                                                      |
|     SPIa SPIb        SPIz                    SPI 32                  |
|       ^    ^           ^                       ^                     |
|       |    |   . . .   |                       |                     |
|  ------------------------------------------------------------------  |
| /     |    |           |                       |                   \ |
| |     |    |   . . .   |                       |                   | |
| |  ------------------------     ---------------------------------  | |
| | /   |    |           |   \   /               |                 \ | |
| | |   |    |           |   |   |   SEI         |                 | | |
| | |   |    |   . . .   |   |   |       ________|_______          | | |
| | |   |    |           |   |   |      /___SEI_SECR_____\         | | |
| | |   |____|___________|   |   |     /       |         \\        | | |
| | |    \_GICP_SETSPI _/    |   |    /        |          \\       | | |
| | |                ||      |   |   /   ...   |           \\      | | |
| | \  GICP          ||      /   \  |          |            \\     / | |
| |  ----------------||------     --|----------|------------||-----  | |
| |                  ||             |          |            ||       | |
| \   GIC            ||             |    ...   |            ||       / |
|  ------------------||-------------^----------^------------||-------  |
|                    ||             |          |            ||         |
|                     \\_______   int 0  ... int 20        //          |
|                      \_NSR__ \                          //           |
|                              \\    ____________________//            |
|                               \\  /________SEI_________/             |
|   AP 806                       \\//                                  |
\                                 ||                                   /
 ---------------------------------||-----------------------------------
                                  ||
                                  || Interconnect
                                  ||\
                                  ||\\______
                                  || \______ <---> Others CP 110
                                  ||
 ---------------------------------||----------------------------------
/                                 ||                                   \
|   CP 110                        ||                                   |
|                                 ||                                   |
|        -------------------------||------------------------           |
|       /                         || MSI                    \          |
|       |   ICU                   ||                        |          |
|       |         /--------------/  \------\                |          |
|       |        /      /-------/           \               |          |
|       |       /      /       /             \              |          |
|       |      /      /       /     . . .     \             |          |
|       |     /      /       /                 \            |          |
|       |   NSR     NSR     SEI               NSR           |          |
|       \    |       |       |                 |            /          |
|        ----^-------^-------^-----------------^------------           |
|            |       |       |                 |                       |
|            |       |       |      . . .      |                       |
|            |       |       |                 |                       |
|         int 0   int 1   int 2             int 206                    |
|                                                                      |
\                                                                      /
 ----------------------------------------------------------------------



Thank you,
Miquèl


Miquel Raynal (17):
  dt-bindings/interrupt-controller: fix Marvell ICU length in the
    example
  arm64: dts: marvell: fix CP110 ICU node size
  arm64: dts: marvell: add syscon compatible to CP110 ICU node
  irqchip/irq-mvebu-icu: fix wrong user data retrieval
  irqchip/irq-mvebu-icu: clarify the reset operation of configured
    interrupts
  irqchip/irq-mvebu-icu: switch to regmap
  irqchip/irq-mvebu-icu: make irq_domain local
  irqchip/irq-mvebu-icu: disociate ICU and NSR
  irqchip/irq-mvebu-icu: support ICU subnodes
  irqchip/irq-mvebu-sei: add new driver for Marvell SEI
  arm64: marvell: enable SEI driver
  irqchip/irq-mvebu-icu: add support for System Error Interrupts (SEI)
  dt-bindings/interrupt-controller: update Marvell ICU bindings
  dt-bindings/interrupt-controller: add description for Marvell SEI node
  arm64: dts: marvell: add AP806 SEI subnode
  arm64: dts: marvell: use new bindings for CP110 interrupts
  arm64: dts: marvell: add CP110 ICU SEI subnode

 .../bindings/interrupt-controller/marvell,icu.txt  |  62 ++-
 .../bindings/interrupt-controller/marvell,sei.txt  |  54 +++
 arch/arm64/Kconfig.platforms                       |   1 +
 arch/arm64/boot/dts/marvell/armada-ap806.dtsi      |  19 +
 arch/arm64/boot/dts/marvell/armada-cp110.dtsi      | 125 +++---
 drivers/irqchip/Kconfig                            |   3 +
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-mvebu-icu.c                    | 294 ++++++++++----
 drivers/irqchip/irq-mvebu-sei.c                    | 449 +++++++++++++++++++++
 drivers/irqchip/irq-mvebu-sei.h                    |  12 +
 10 files changed, 877 insertions(+), 143 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
 create mode 100644 drivers/irqchip/irq-mvebu-sei.c
 create mode 100644 drivers/irqchip/irq-mvebu-sei.h

-- 
2.14.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 00/17] Add System Error Interrupt support to Armada SoCs
@ 2018-04-21 13:55 ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

The ICU is an IRQ chip found in Armada CP110. It currently has 207 wired
inputs. Its purpose is to aggregate all CP interrupts and report them to
the AP through MSIs. The ICU writes into GIC registers (AP side) by way
of the interconnect. These interrupts can be of several groups:
- SecuRe (SR);
- Non-SecuRe (NSR);
- System Error Interrupts (SEI);
- RAM Error Interrupts (REI);
- ...
Each ICU wired interrupt can be of any of these groups. The group is
encoded in the MSI payload.

Until now, only the non-secure interrupts (NSR) were handled by the ICU
driver. Interrupts of another group could work by chance because the
ICU driver does not erase all ATF configuration; it only erases the
configuration for NSR interrupts.

This series aims at adding support for the System Error Interrupts
(SEI). For this purpose, the ICU driver is a bit reworked to separate
the ICU 'generic' configuration from the NSR-related handling. Then,
the SEI driver (part of the GIC) is introduced and finally, support for
SEI interrupts are also added to the ICU driver.

The SEI driver is a bit different than its cousin the GICP because it
must handle MSIs from the CPs, as well as wired interrupts from the AP
itself. MSIs and wired interrupts will automatically update two
registers (GICP_SECR0/GICP_SECR1) that will trigger a single top-level
interrupt (SPI #32).

As this is my first contribution in the IRQ subsystem I might have
missed some specificities or misunderstood the API, please do not
hesitate to correct me if I'm wrong.

Also, for the sake of understandability (and because I love ASCII art),
this is a try to explain the ICU/SEI architecture:


 ---------------------------------------------------------------------
/                                                                      \
|                                                                      |
|     SPIa SPIb        SPIz                    SPI 32                  |
|       ^    ^           ^                       ^                     |
|       |    |   . . .   |                       |                     |
|  ------------------------------------------------------------------  |
| /     |    |           |                       |                   \ |
| |     |    |   . . .   |                       |                   | |
| |  ------------------------     ---------------------------------  | |
| | /   |    |           |   \   /               |                 \ | |
| | |   |    |           |   |   |   SEI         |                 | | |
| | |   |    |   . . .   |   |   |       ________|_______          | | |
| | |   |    |           |   |   |      /___SEI_SECR_____\         | | |
| | |   |____|___________|   |   |     /       |         \\        | | |
| | |    \_GICP_SETSPI _/    |   |    /        |          \\       | | |
| | |                ||      |   |   /   ...   |           \\      | | |
| | \  GICP          ||      /   \  |          |            \\     / | |
| |  ----------------||------     --|----------|------------||-----  | |
| |                  ||             |          |            ||       | |
| \   GIC            ||             |    ...   |            ||       / |
|  ------------------||-------------^----------^------------||-------  |
|                    ||             |          |            ||         |
|                     \\_______   int 0  ... int 20        //          |
|                      \_NSR__ \                          //           |
|                              \\    ____________________//            |
|                               \\  /________SEI_________/             |
|   AP 806                       \\//                                  |
\                                 ||                                   /
 ---------------------------------||-----------------------------------
                                  ||
                                  || Interconnect
                                  ||\
                                  ||\\______
                                  || \______ <---> Others CP 110
                                  ||
 ---------------------------------||----------------------------------
/                                 ||                                   \
|   CP 110                        ||                                   |
|                                 ||                                   |
|        -------------------------||------------------------           |
|       /                         || MSI                    \          |
|       |   ICU                   ||                        |          |
|       |         /--------------/  \------\                |          |
|       |        /      /-------/           \               |          |
|       |       /      /       /             \              |          |
|       |      /      /       /     . . .     \             |          |
|       |     /      /       /                 \            |          |
|       |   NSR     NSR     SEI               NSR           |          |
|       \    |       |       |                 |            /          |
|        ----^-------^-------^-----------------^------------           |
|            |       |       |                 |                       |
|            |       |       |      . . .      |                       |
|            |       |       |                 |                       |
|         int 0   int 1   int 2             int 206                    |
|                                                                      |
\                                                                      /
 ----------------------------------------------------------------------



Thank you,
Miqu?l


Miquel Raynal (17):
  dt-bindings/interrupt-controller: fix Marvell ICU length in the
    example
  arm64: dts: marvell: fix CP110 ICU node size
  arm64: dts: marvell: add syscon compatible to CP110 ICU node
  irqchip/irq-mvebu-icu: fix wrong user data retrieval
  irqchip/irq-mvebu-icu: clarify the reset operation of configured
    interrupts
  irqchip/irq-mvebu-icu: switch to regmap
  irqchip/irq-mvebu-icu: make irq_domain local
  irqchip/irq-mvebu-icu: disociate ICU and NSR
  irqchip/irq-mvebu-icu: support ICU subnodes
  irqchip/irq-mvebu-sei: add new driver for Marvell SEI
  arm64: marvell: enable SEI driver
  irqchip/irq-mvebu-icu: add support for System Error Interrupts (SEI)
  dt-bindings/interrupt-controller: update Marvell ICU bindings
  dt-bindings/interrupt-controller: add description for Marvell SEI node
  arm64: dts: marvell: add AP806 SEI subnode
  arm64: dts: marvell: use new bindings for CP110 interrupts
  arm64: dts: marvell: add CP110 ICU SEI subnode

 .../bindings/interrupt-controller/marvell,icu.txt  |  62 ++-
 .../bindings/interrupt-controller/marvell,sei.txt  |  54 +++
 arch/arm64/Kconfig.platforms                       |   1 +
 arch/arm64/boot/dts/marvell/armada-ap806.dtsi      |  19 +
 arch/arm64/boot/dts/marvell/armada-cp110.dtsi      | 125 +++---
 drivers/irqchip/Kconfig                            |   3 +
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-mvebu-icu.c                    | 294 ++++++++++----
 drivers/irqchip/irq-mvebu-sei.c                    | 449 +++++++++++++++++++++
 drivers/irqchip/irq-mvebu-sei.h                    |  12 +
 10 files changed, 877 insertions(+), 143 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
 create mode 100644 drivers/irqchip/irq-mvebu-sei.c
 create mode 100644 drivers/irqchip/irq-mvebu-sei.h

-- 
2.14.1

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

* [PATCH 01/17] dt-bindings/interrupt-controller: fix Marvell ICU length in the example
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
specification).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
index aa8bf2ec8905..649b7ec9d9b1 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
@@ -39,7 +39,7 @@ Example:
 
 icu: interrupt-controller@1e0000 {
 	compatible = "marvell,cp110-icu";
-	reg = <0x1e0000 0x10>;
+	reg = <0x1e0000 0x440>;
 	#interrupt-cells = <3>;
 	interrupt-controller;
 	msi-parent = <&gicp>;
-- 
2.14.1

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

* [PATCH 01/17] dt-bindings/interrupt-controller: fix Marvell ICU length in the example
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
specification).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
index aa8bf2ec8905..649b7ec9d9b1 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
@@ -39,7 +39,7 @@ Example:
 
 icu: interrupt-controller at 1e0000 {
 	compatible = "marvell,cp110-icu";
-	reg = <0x1e0000 0x10>;
+	reg = <0x1e0000 0x440>;
 	#interrupt-cells = <3>;
 	interrupt-controller;
 	msi-parent = <&gicp>;
-- 
2.14.1

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

* [PATCH 02/17] arm64: dts: marvell: fix CP110 ICU node size
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
specification).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/boot/dts/marvell/armada-cp110.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
index 48cad7919efa..9fa41c54f69c 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
@@ -146,7 +146,7 @@
 
 		CP110_LABEL(icu): interrupt-controller@1e0000 {
 			compatible = "marvell,cp110-icu";
-			reg = <0x1e0000 0x10>;
+			reg = <0x1e0000 0x440>;
 			#interrupt-cells = <3>;
 			interrupt-controller;
 			msi-parent = <&gicp>;
-- 
2.14.1

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

* [PATCH 02/17] arm64: dts: marvell: fix CP110 ICU node size
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
specification).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/boot/dts/marvell/armada-cp110.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
index 48cad7919efa..9fa41c54f69c 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
@@ -146,7 +146,7 @@
 
 		CP110_LABEL(icu): interrupt-controller at 1e0000 {
 			compatible = "marvell,cp110-icu";
-			reg = <0x1e0000 0x10>;
+			reg = <0x1e0000 0x440>;
 			#interrupt-cells = <3>;
 			interrupt-controller;
 			msi-parent = <&gicp>;
-- 
2.14.1

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

* [PATCH 03/17] arm64: dts: marvell: add syscon compatible to CP110 ICU node
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Prepare the migration to new bindings where the ICU node has several
subnodes: one per interrupt group (NSR, SEI, REI, etc). The code for
each node will share the same set of registers. Turning the ICU node
into a syscon is a clean solution to handle that.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/boot/dts/marvell/armada-cp110.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
index 9fa41c54f69c..9323acdb712f 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
@@ -145,7 +145,7 @@
 		};
 
 		CP110_LABEL(icu): interrupt-controller@1e0000 {
-			compatible = "marvell,cp110-icu";
+			compatible = "marvell,cp110-icu", "syscon";
 			reg = <0x1e0000 0x440>;
 			#interrupt-cells = <3>;
 			interrupt-controller;
-- 
2.14.1

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

* [PATCH 03/17] arm64: dts: marvell: add syscon compatible to CP110 ICU node
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

Prepare the migration to new bindings where the ICU node has several
subnodes: one per interrupt group (NSR, SEI, REI, etc). The code for
each node will share the same set of registers. Turning the ICU node
into a syscon is a clean solution to handle that.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/boot/dts/marvell/armada-cp110.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
index 9fa41c54f69c..9323acdb712f 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
@@ -145,7 +145,7 @@
 		};
 
 		CP110_LABEL(icu): interrupt-controller at 1e0000 {
-			compatible = "marvell,cp110-icu";
+			compatible = "marvell,cp110-icu", "syscon";
 			reg = <0x1e0000 0x440>;
 			#interrupt-cells = <3>;
 			interrupt-controller;
-- 
2.14.1

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

* [PATCH 04/17] irqchip/irq-mvebu-icu: fix wrong user data retrieval
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

The irq_domain structure has an host_data pointer that just stores user
data. It is meant to not be touched by the IRQ core. However, when it
comes to MSI, the MSI layer adds its own private data there with a
structure that also has a host_data pointer.

Because this IRQ domain is an MSI domain, to access user data we should
do a d->host_data->host_data, also wrapped as
'platform_msi_get_host_data()'.

This bug was lying there silently because the 'icu' structure retrieved
this way was just called by dev_err(), only producing a
'(NULL device *):' output on the console.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index e18c48d3a92e..6a77b9ea8e41 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -92,7 +92,7 @@ static int
 mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
 			       unsigned long *hwirq, unsigned int *type)
 {
-	struct mvebu_icu *icu = d->host_data;
+	struct mvebu_icu *icu = platform_msi_get_host_data(d);
 	unsigned int icu_group;
 
 	/* Check the count of the parameters in dt */
-- 
2.14.1

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

* [PATCH 04/17] irqchip/irq-mvebu-icu: fix wrong user data retrieval
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

The irq_domain structure has an host_data pointer that just stores user
data. It is meant to not be touched by the IRQ core. However, when it
comes to MSI, the MSI layer adds its own private data there with a
structure that also has a host_data pointer.

Because this IRQ domain is an MSI domain, to access user data we should
do a d->host_data->host_data, also wrapped as
'platform_msi_get_host_data()'.

This bug was lying there silently because the 'icu' structure retrieved
this way was just called by dev_err(), only producing a
'(NULL device *):' output on the console.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index e18c48d3a92e..6a77b9ea8e41 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -92,7 +92,7 @@ static int
 mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
 			       unsigned long *hwirq, unsigned int *type)
 {
-	struct mvebu_icu *icu = d->host_data;
+	struct mvebu_icu *icu = platform_msi_get_host_data(d);
 	unsigned int icu_group;
 
 	/* Check the count of the parameters in dt */
-- 
2.14.1

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

* [PATCH 05/17] irqchip/irq-mvebu-icu: clarify the reset operation of configured interrupts
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Rewrite a small section to clarify the reset operation of interrupts
already configured by ATF that we want to handle in the driver. This
will simplify the introduction of System Error Interrupts support.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 6a77b9ea8e41..5af2520445c4 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -198,8 +198,8 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	struct device_node *gicp_dn;
 	struct resource *res;
 	phys_addr_t setspi, clrspi;
-	u32 i, icu_int;
 	int ret;
+	u32 i;
 
 	icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu),
 			   GFP_KERNEL);
@@ -257,8 +257,12 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	 * avoid unpredictable SPI assignments done by firmware.
 	 */
 	for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
+		u32 icu_int, icu_grp;
+
 		icu_int = readl(icu->base + ICU_INT_CFG(i));
-		if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR)
+		icu_grp = icu_int >> ICU_GROUP_SHIFT;
+
+		if (icu_grp == ICU_GRP_NSR)
 			writel_relaxed(0x0, icu->base + ICU_INT_CFG(i));
 	}
 
-- 
2.14.1

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

* [PATCH 05/17] irqchip/irq-mvebu-icu: clarify the reset operation of configured interrupts
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

Rewrite a small section to clarify the reset operation of interrupts
already configured by ATF that we want to handle in the driver. This
will simplify the introduction of System Error Interrupts support.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 6a77b9ea8e41..5af2520445c4 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -198,8 +198,8 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	struct device_node *gicp_dn;
 	struct resource *res;
 	phys_addr_t setspi, clrspi;
-	u32 i, icu_int;
 	int ret;
+	u32 i;
 
 	icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu),
 			   GFP_KERNEL);
@@ -257,8 +257,12 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	 * avoid unpredictable SPI assignments done by firmware.
 	 */
 	for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
+		u32 icu_int, icu_grp;
+
 		icu_int = readl(icu->base + ICU_INT_CFG(i));
-		if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR)
+		icu_grp = icu_int >> ICU_GROUP_SHIFT;
+
+		if (icu_grp == ICU_GRP_NSR)
 			writel_relaxed(0x0, icu->base + ICU_INT_CFG(i));
 	}
 
-- 
2.14.1

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

* [PATCH 06/17] irqchip/irq-mvebu-icu: switch to regmap
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

The ICU DT nodes have now the 'syscon' compatible, we can switch to
regmap before splitting the code to support multiple platform devices to
be probed (one for the ICU, one per interrupt group).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 37 ++++++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 5af2520445c4..580586240781 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -18,6 +18,8 @@
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
 
 #include <dt-bindings/interrupt-controller/mvebu-icu.h>
 
@@ -40,7 +42,7 @@
 
 struct mvebu_icu {
 	struct irq_chip irq_chip;
-	void __iomem *base;
+	struct regmap *regmap;
 	struct irq_domain *domain;
 	struct device *dev;
 };
@@ -69,7 +71,7 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
 		icu_int = 0;
 	}
 
-	writel_relaxed(icu_int, icu->base + ICU_INT_CFG(d->hwirq));
+	regmap_write(icu->regmap, ICU_INT_CFG(d->hwirq), icu_int);
 
 	/*
 	 * The SATA unit has 2 ports, and a dedicated ICU entry per
@@ -81,10 +83,10 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
 	 * configured (regardless of which port is actually in use).
 	 */
 	if (d->hwirq == ICU_SATA0_ICU_ID || d->hwirq == ICU_SATA1_ICU_ID) {
-		writel_relaxed(icu_int,
-			       icu->base + ICU_INT_CFG(ICU_SATA0_ICU_ID));
-		writel_relaxed(icu_int,
-			       icu->base + ICU_INT_CFG(ICU_SATA1_ICU_ID));
+		regmap_write(icu->regmap, ICU_INT_CFG(ICU_SATA0_ICU_ID),
+			     icu_int);
+		regmap_write(icu->regmap, ICU_INT_CFG(ICU_SATA1_ICU_ID),
+			     icu_int);
 	}
 }
 
@@ -208,12 +210,13 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 
 	icu->dev = &pdev->dev;
 
+	icu->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, NULL);
+	if (IS_ERR(icu->regmap))
+		return PTR_ERR(icu->regmap);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	icu->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(icu->base)) {
-		dev_err(&pdev->dev, "Failed to map icu base address.\n");
-		return PTR_ERR(icu->base);
-	}
+	if (!res)
+		return -ENODEV;
 
 	icu->irq_chip.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
 					    "ICU.%x",
@@ -247,10 +250,10 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 		return ret;
 
 	/* Set Clear/Set ICU SPI message address in AP */
-	writel_relaxed(upper_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AH);
-	writel_relaxed(lower_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AL);
-	writel_relaxed(upper_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AH);
-	writel_relaxed(lower_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AL);
+	regmap_write(icu->regmap, ICU_SETSPI_NSR_AH, upper_32_bits(setspi));
+	regmap_write(icu->regmap, ICU_SETSPI_NSR_AL, lower_32_bits(setspi));
+	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AH, upper_32_bits(clrspi));
+	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AL, lower_32_bits(clrspi));
 
 	/*
 	 * Clean all ICU interrupts with type SPI_NSR, required to
@@ -259,11 +262,11 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
 		u32 icu_int, icu_grp;
 
-		icu_int = readl(icu->base + ICU_INT_CFG(i));
+		regmap_read(icu->regmap, ICU_INT_CFG(i), &icu_int);
 		icu_grp = icu_int >> ICU_GROUP_SHIFT;
 
 		if (icu_grp == ICU_GRP_NSR)
-			writel_relaxed(0x0, icu->base + ICU_INT_CFG(i));
+			regmap_write(icu->regmap, ICU_INT_CFG(i), 0);
 	}
 
 	icu->domain =
-- 
2.14.1

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

* [PATCH 06/17] irqchip/irq-mvebu-icu: switch to regmap
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

The ICU DT nodes have now the 'syscon' compatible, we can switch to
regmap before splitting the code to support multiple platform devices to
be probed (one for the ICU, one per interrupt group).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 37 ++++++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 5af2520445c4..580586240781 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -18,6 +18,8 @@
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
 
 #include <dt-bindings/interrupt-controller/mvebu-icu.h>
 
@@ -40,7 +42,7 @@
 
 struct mvebu_icu {
 	struct irq_chip irq_chip;
-	void __iomem *base;
+	struct regmap *regmap;
 	struct irq_domain *domain;
 	struct device *dev;
 };
@@ -69,7 +71,7 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
 		icu_int = 0;
 	}
 
-	writel_relaxed(icu_int, icu->base + ICU_INT_CFG(d->hwirq));
+	regmap_write(icu->regmap, ICU_INT_CFG(d->hwirq), icu_int);
 
 	/*
 	 * The SATA unit has 2 ports, and a dedicated ICU entry per
@@ -81,10 +83,10 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
 	 * configured (regardless of which port is actually in use).
 	 */
 	if (d->hwirq == ICU_SATA0_ICU_ID || d->hwirq == ICU_SATA1_ICU_ID) {
-		writel_relaxed(icu_int,
-			       icu->base + ICU_INT_CFG(ICU_SATA0_ICU_ID));
-		writel_relaxed(icu_int,
-			       icu->base + ICU_INT_CFG(ICU_SATA1_ICU_ID));
+		regmap_write(icu->regmap, ICU_INT_CFG(ICU_SATA0_ICU_ID),
+			     icu_int);
+		regmap_write(icu->regmap, ICU_INT_CFG(ICU_SATA1_ICU_ID),
+			     icu_int);
 	}
 }
 
@@ -208,12 +210,13 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 
 	icu->dev = &pdev->dev;
 
+	icu->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, NULL);
+	if (IS_ERR(icu->regmap))
+		return PTR_ERR(icu->regmap);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	icu->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(icu->base)) {
-		dev_err(&pdev->dev, "Failed to map icu base address.\n");
-		return PTR_ERR(icu->base);
-	}
+	if (!res)
+		return -ENODEV;
 
 	icu->irq_chip.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
 					    "ICU.%x",
@@ -247,10 +250,10 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 		return ret;
 
 	/* Set Clear/Set ICU SPI message address in AP */
-	writel_relaxed(upper_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AH);
-	writel_relaxed(lower_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AL);
-	writel_relaxed(upper_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AH);
-	writel_relaxed(lower_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AL);
+	regmap_write(icu->regmap, ICU_SETSPI_NSR_AH, upper_32_bits(setspi));
+	regmap_write(icu->regmap, ICU_SETSPI_NSR_AL, lower_32_bits(setspi));
+	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AH, upper_32_bits(clrspi));
+	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AL, lower_32_bits(clrspi));
 
 	/*
 	 * Clean all ICU interrupts with type SPI_NSR, required to
@@ -259,11 +262,11 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
 		u32 icu_int, icu_grp;
 
-		icu_int = readl(icu->base + ICU_INT_CFG(i));
+		regmap_read(icu->regmap, ICU_INT_CFG(i), &icu_int);
 		icu_grp = icu_int >> ICU_GROUP_SHIFT;
 
 		if (icu_grp == ICU_GRP_NSR)
-			writel_relaxed(0x0, icu->base + ICU_INT_CFG(i));
+			regmap_write(icu->regmap, ICU_INT_CFG(i), 0);
 	}
 
 	icu->domain =
-- 
2.14.1

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

* [PATCH 07/17] irqchip/irq-mvebu-icu: make irq_domain local
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Make the current MSI irq_domain local to ease the split between ICU
platform device code and NSR platform device code.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 580586240781..493c9625d48b 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -43,7 +43,6 @@
 struct mvebu_icu {
 	struct irq_chip irq_chip;
 	struct regmap *regmap;
-	struct irq_domain *domain;
 	struct device *dev;
 };
 
@@ -198,6 +197,7 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	struct mvebu_icu *icu;
 	struct device_node *node = pdev->dev.of_node;
 	struct device_node *gicp_dn;
+	struct irq_domain *irq_domain;
 	struct resource *res;
 	phys_addr_t setspi, clrspi;
 	int ret;
@@ -269,11 +269,11 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 			regmap_write(icu->regmap, ICU_INT_CFG(i), 0);
 	}
 
-	icu->domain =
+	irq_domain =
 		platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS,
 						  mvebu_icu_write_msg,
 						  &mvebu_icu_domain_ops, icu);
-	if (!icu->domain) {
+	if (!irq_domain) {
 		dev_err(&pdev->dev, "Failed to create ICU domain\n");
 		return -ENOMEM;
 	}
-- 
2.14.1

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

* [PATCH 07/17] irqchip/irq-mvebu-icu: make irq_domain local
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

Make the current MSI irq_domain local to ease the split between ICU
platform device code and NSR platform device code.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 580586240781..493c9625d48b 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -43,7 +43,6 @@
 struct mvebu_icu {
 	struct irq_chip irq_chip;
 	struct regmap *regmap;
-	struct irq_domain *domain;
 	struct device *dev;
 };
 
@@ -198,6 +197,7 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	struct mvebu_icu *icu;
 	struct device_node *node = pdev->dev.of_node;
 	struct device_node *gicp_dn;
+	struct irq_domain *irq_domain;
 	struct resource *res;
 	phys_addr_t setspi, clrspi;
 	int ret;
@@ -269,11 +269,11 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 			regmap_write(icu->regmap, ICU_INT_CFG(i), 0);
 	}
 
-	icu->domain =
+	irq_domain =
 		platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS,
 						  mvebu_icu_write_msg,
 						  &mvebu_icu_domain_ops, icu);
-	if (!icu->domain) {
+	if (!irq_domain) {
 		dev_err(&pdev->dev, "Failed to create ICU domain\n");
 		return -ENOMEM;
 	}
-- 
2.14.1

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

* [PATCH 08/17] irqchip/irq-mvebu-icu: disociate ICU and NSR
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

NSR (non-secure interrupts) are handled in the ICU driver like if there
was only this type of interrupt in the ICU. Change this behavior to
prepare the introduction of SEI (System Error Interrupts) support by
moving the NSR code in a separate function. This is done under the form
of a 'probe' function to ease future migration to NSR/SEI being platform
devices part of the ICU.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 84 ++++++++++++++++++++++-------------------
 1 file changed, 46 insertions(+), 38 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 493c9625d48b..c919110dcee5 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -192,15 +192,53 @@ static const struct irq_domain_ops mvebu_icu_domain_ops = {
 	.free      = mvebu_icu_irq_domain_free,
 };
 
-static int mvebu_icu_probe(struct platform_device *pdev)
+static int mvebu_icu_nsr_probe(struct platform_device *pdev)
 {
-	struct mvebu_icu *icu;
-	struct device_node *node = pdev->dev.of_node;
-	struct device_node *gicp_dn;
+	struct device_node *msi_parent_dn;
 	struct irq_domain *irq_domain;
-	struct resource *res;
-	phys_addr_t setspi, clrspi;
+	struct mvebu_icu *icu;
+	phys_addr_t set, clr;
 	int ret;
+
+	icu = dev_get_drvdata(&pdev->dev);
+	if (!icu)
+		return -ENODEV;
+
+	pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, pdev->dev.of_node,
+						 DOMAIN_BUS_PLATFORM_MSI);
+	if (!pdev->dev.msi_domain)
+		return -EPROBE_DEFER;
+
+	msi_parent_dn = irq_domain_get_of_node(pdev->dev.msi_domain);
+	if (!msi_parent_dn)
+		return -ENODEV;
+
+	/* Set Clear/Set ICU NSR SPI message address in AP */
+	ret = mvebu_gicp_get_doorbells(msi_parent_dn, &set, &clr);
+	if (ret)
+		return ret;
+
+	regmap_write(icu->regmap, ICU_SETSPI_NSR_AH, upper_32_bits(set));
+	regmap_write(icu->regmap, ICU_SETSPI_NSR_AL, lower_32_bits(set));
+	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AH, upper_32_bits(clr));
+	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AL, lower_32_bits(clr));
+
+	irq_domain = platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS,
+						       mvebu_icu_write_msg,
+						       &mvebu_icu_domain_ops,
+						       icu);
+	if (!irq_domain) {
+		dev_err(&pdev->dev, "Failed to create ICU MSI domain\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int mvebu_icu_probe(struct platform_device *pdev)
+{
+	struct mvebu_icu *icu;
+	struct resource *res;
 	u32 i;
 
 	icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu),
@@ -232,29 +270,6 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	icu->irq_chip.irq_set_affinity = irq_chip_set_affinity_parent;
 #endif
 
-	/*
-	 * We're probed after MSI domains have been resolved, so force
-	 * resolution here.
-	 */
-	pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, node,
-						 DOMAIN_BUS_PLATFORM_MSI);
-	if (!pdev->dev.msi_domain)
-		return -EPROBE_DEFER;
-
-	gicp_dn = irq_domain_get_of_node(pdev->dev.msi_domain);
-	if (!gicp_dn)
-		return -ENODEV;
-
-	ret = mvebu_gicp_get_doorbells(gicp_dn, &setspi, &clrspi);
-	if (ret)
-		return ret;
-
-	/* Set Clear/Set ICU SPI message address in AP */
-	regmap_write(icu->regmap, ICU_SETSPI_NSR_AH, upper_32_bits(setspi));
-	regmap_write(icu->regmap, ICU_SETSPI_NSR_AL, lower_32_bits(setspi));
-	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AH, upper_32_bits(clrspi));
-	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AL, lower_32_bits(clrspi));
-
 	/*
 	 * Clean all ICU interrupts with type SPI_NSR, required to
 	 * avoid unpredictable SPI assignments done by firmware.
@@ -269,16 +284,9 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 			regmap_write(icu->regmap, ICU_INT_CFG(i), 0);
 	}
 
-	irq_domain =
-		platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS,
-						  mvebu_icu_write_msg,
-						  &mvebu_icu_domain_ops, icu);
-	if (!irq_domain) {
-		dev_err(&pdev->dev, "Failed to create ICU domain\n");
-		return -ENOMEM;
-	}
+	platform_set_drvdata(pdev, icu);
 
-	return 0;
+	return mvebu_icu_nsr_probe(pdev);
 }
 
 static const struct of_device_id mvebu_icu_of_match[] = {
-- 
2.14.1

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

* [PATCH 08/17] irqchip/irq-mvebu-icu: disociate ICU and NSR
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

NSR (non-secure interrupts) are handled in the ICU driver like if there
was only this type of interrupt in the ICU. Change this behavior to
prepare the introduction of SEI (System Error Interrupts) support by
moving the NSR code in a separate function. This is done under the form
of a 'probe' function to ease future migration to NSR/SEI being platform
devices part of the ICU.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 84 ++++++++++++++++++++++-------------------
 1 file changed, 46 insertions(+), 38 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 493c9625d48b..c919110dcee5 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -192,15 +192,53 @@ static const struct irq_domain_ops mvebu_icu_domain_ops = {
 	.free      = mvebu_icu_irq_domain_free,
 };
 
-static int mvebu_icu_probe(struct platform_device *pdev)
+static int mvebu_icu_nsr_probe(struct platform_device *pdev)
 {
-	struct mvebu_icu *icu;
-	struct device_node *node = pdev->dev.of_node;
-	struct device_node *gicp_dn;
+	struct device_node *msi_parent_dn;
 	struct irq_domain *irq_domain;
-	struct resource *res;
-	phys_addr_t setspi, clrspi;
+	struct mvebu_icu *icu;
+	phys_addr_t set, clr;
 	int ret;
+
+	icu = dev_get_drvdata(&pdev->dev);
+	if (!icu)
+		return -ENODEV;
+
+	pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, pdev->dev.of_node,
+						 DOMAIN_BUS_PLATFORM_MSI);
+	if (!pdev->dev.msi_domain)
+		return -EPROBE_DEFER;
+
+	msi_parent_dn = irq_domain_get_of_node(pdev->dev.msi_domain);
+	if (!msi_parent_dn)
+		return -ENODEV;
+
+	/* Set Clear/Set ICU NSR SPI message address in AP */
+	ret = mvebu_gicp_get_doorbells(msi_parent_dn, &set, &clr);
+	if (ret)
+		return ret;
+
+	regmap_write(icu->regmap, ICU_SETSPI_NSR_AH, upper_32_bits(set));
+	regmap_write(icu->regmap, ICU_SETSPI_NSR_AL, lower_32_bits(set));
+	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AH, upper_32_bits(clr));
+	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AL, lower_32_bits(clr));
+
+	irq_domain = platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS,
+						       mvebu_icu_write_msg,
+						       &mvebu_icu_domain_ops,
+						       icu);
+	if (!irq_domain) {
+		dev_err(&pdev->dev, "Failed to create ICU MSI domain\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int mvebu_icu_probe(struct platform_device *pdev)
+{
+	struct mvebu_icu *icu;
+	struct resource *res;
 	u32 i;
 
 	icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu),
@@ -232,29 +270,6 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	icu->irq_chip.irq_set_affinity = irq_chip_set_affinity_parent;
 #endif
 
-	/*
-	 * We're probed after MSI domains have been resolved, so force
-	 * resolution here.
-	 */
-	pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, node,
-						 DOMAIN_BUS_PLATFORM_MSI);
-	if (!pdev->dev.msi_domain)
-		return -EPROBE_DEFER;
-
-	gicp_dn = irq_domain_get_of_node(pdev->dev.msi_domain);
-	if (!gicp_dn)
-		return -ENODEV;
-
-	ret = mvebu_gicp_get_doorbells(gicp_dn, &setspi, &clrspi);
-	if (ret)
-		return ret;
-
-	/* Set Clear/Set ICU SPI message address in AP */
-	regmap_write(icu->regmap, ICU_SETSPI_NSR_AH, upper_32_bits(setspi));
-	regmap_write(icu->regmap, ICU_SETSPI_NSR_AL, lower_32_bits(setspi));
-	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AH, upper_32_bits(clrspi));
-	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AL, lower_32_bits(clrspi));
-
 	/*
 	 * Clean all ICU interrupts with type SPI_NSR, required to
 	 * avoid unpredictable SPI assignments done by firmware.
@@ -269,16 +284,9 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 			regmap_write(icu->regmap, ICU_INT_CFG(i), 0);
 	}
 
-	irq_domain =
-		platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS,
-						  mvebu_icu_write_msg,
-						  &mvebu_icu_domain_ops, icu);
-	if (!irq_domain) {
-		dev_err(&pdev->dev, "Failed to create ICU domain\n");
-		return -ENOMEM;
-	}
+	platform_set_drvdata(pdev, icu);
 
-	return 0;
+	return mvebu_icu_nsr_probe(pdev);
 }
 
 static const struct of_device_id mvebu_icu_of_match[] = {
-- 
2.14.1

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

* [PATCH 09/17] irqchip/irq-mvebu-icu: support ICU subnodes
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Introduce new bindings for the ICU.

Each DT subnode of the ICU represents a type of interrupt that should
be handled separately. Add the possibility for the ICU to have subnodes
and probe each of them automatically with devm_platform_populate(). If
the node as no child, the probe function for NSRs will still be called
'manually'.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 85 +++++++++++++++++++++++++++++++++--------
 1 file changed, 70 insertions(+), 15 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index c919110dcee5..1d3cd112619c 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -44,6 +44,7 @@ struct mvebu_icu {
 	struct irq_chip irq_chip;
 	struct regmap *regmap;
 	struct device *dev;
+	bool legacy_bindings;
 };
 
 struct mvebu_icu_irq_data {
@@ -52,6 +53,27 @@ struct mvebu_icu_irq_data {
 	unsigned int type;
 };
 
+static struct mvebu_icu *mvebu_dev_get_drvdata(struct platform_device *pdev)
+{
+	struct mvebu_icu *icu;
+
+	icu = dev_get_drvdata(&pdev->dev);
+	if (icu) {
+		/* Legacy bindings: get the device data */
+		if (!icu->legacy_bindings)
+			return ERR_PTR(-EINVAL);
+	} else {
+		/* New bindings: get the parent device (ICU) data */
+		icu = dev_get_drvdata(pdev->dev.parent);
+		if (!icu)
+			return ERR_PTR(-ENODEV);
+		if (icu->legacy_bindings)
+			return ERR_PTR(-EINVAL);
+	}
+
+	return icu;
+}
+
 static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
 {
 	struct irq_data *d = irq_get_irq_data(desc->irq);
@@ -94,31 +116,35 @@ mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
 			       unsigned long *hwirq, unsigned int *type)
 {
 	struct mvebu_icu *icu = platform_msi_get_host_data(d);
-	unsigned int icu_group;
+	unsigned int param_count = icu->legacy_bindings ? 3 : 2;
 
 	/* Check the count of the parameters in dt */
-	if (WARN_ON(fwspec->param_count < 3)) {
+	if (WARN_ON(fwspec->param_count != param_count)) {
 		dev_err(icu->dev, "wrong ICU parameter count %d\n",
 			fwspec->param_count);
 		return -EINVAL;
 	}
 
-	/* Only ICU group type is handled */
-	icu_group = fwspec->param[0];
-	if (icu_group != ICU_GRP_NSR && icu_group != ICU_GRP_SR &&
-	    icu_group != ICU_GRP_SEI && icu_group != ICU_GRP_REI) {
-		dev_err(icu->dev, "wrong ICU group type %x\n", icu_group);
-		return -EINVAL;
+	if (icu->legacy_bindings) {
+		*hwirq = fwspec->param[1];
+		*type = fwspec->param[2];
+		if (fwspec->param[0] != ICU_GRP_NSR) {
+			dev_err(icu->dev, "wrong ICU group type %x\n",
+				fwspec->param[0]);
+			return -EINVAL;
+		}
+	} else {
+		*hwirq = fwspec->param[0];
+		*type = fwspec->param[1];
 	}
 
-	*hwirq = fwspec->param[1];
 	if (*hwirq >= ICU_MAX_IRQS) {
 		dev_err(icu->dev, "invalid interrupt number %ld\n", *hwirq);
 		return -EINVAL;
 	}
 
 	/* Mask the type to prevent wrong DT configuration */
-	*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+	*type &= IRQ_TYPE_SENSE_MASK;
 
 	return 0;
 }
@@ -144,7 +170,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 		goto free_irqd;
 	}
 
-	icu_irqd->icu_group = fwspec->param[0];
+	if (icu->legacy_bindings)
+		icu_irqd->icu_group = fwspec->param[0];
+	else
+		icu_irqd->icu_group = ICU_GRP_NSR;
 	icu_irqd->icu = icu;
 
 	err = platform_msi_domain_alloc(domain, virq, nr_irqs);
@@ -200,9 +229,9 @@ static int mvebu_icu_nsr_probe(struct platform_device *pdev)
 	phys_addr_t set, clr;
 	int ret;
 
-	icu = dev_get_drvdata(&pdev->dev);
-	if (!icu)
-		return -ENODEV;
+	icu = mvebu_dev_get_drvdata(pdev);
+	if (IS_ERR(icu))
+		return PTR_ERR(icu);
 
 	pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, pdev->dev.of_node,
 						 DOMAIN_BUS_PLATFORM_MSI);
@@ -235,6 +264,20 @@ static int mvebu_icu_nsr_probe(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id mvebu_icu_nsr_of_match[] = {
+	{ .compatible = "marvell,cp110-icu-nsr", },
+	{},
+};
+
+static struct platform_driver mvebu_icu_nsr_driver = {
+	.probe  = mvebu_icu_nsr_probe,
+	.driver = {
+		.name = "mvebu-icu-nsr",
+		.of_match_table = mvebu_icu_nsr_of_match,
+	},
+};
+builtin_platform_driver(mvebu_icu_nsr_driver);
+
 static int mvebu_icu_probe(struct platform_device *pdev)
 {
 	struct mvebu_icu *icu;
@@ -262,6 +305,15 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	if (!icu->irq_chip.name)
 		return -ENOMEM;
 
+	/*
+	 * Legacy bindings: ICU is one node with one MSI parent: force manually
+	 *                  the probe of the NSR interrupts side.
+	 * New bindings: ICU node has children, one per interrupt controller
+	 *               having its own MSI parent: call platform_populate().
+	 */
+	if (!of_get_child_count(pdev->dev.of_node))
+		icu->legacy_bindings = true;
+
 	icu->irq_chip.irq_mask = irq_chip_mask_parent;
 	icu->irq_chip.irq_unmask = irq_chip_unmask_parent;
 	icu->irq_chip.irq_eoi = irq_chip_eoi_parent;
@@ -286,7 +338,10 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, icu);
 
-	return mvebu_icu_nsr_probe(pdev);
+	if (icu->legacy_bindings)
+		return mvebu_icu_nsr_probe(pdev);
+	else
+		return devm_of_platform_populate(&pdev->dev);
 }
 
 static const struct of_device_id mvebu_icu_of_match[] = {
-- 
2.14.1

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

* [PATCH 09/17] irqchip/irq-mvebu-icu: support ICU subnodes
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

Introduce new bindings for the ICU.

Each DT subnode of the ICU represents a type of interrupt that should
be handled separately. Add the possibility for the ICU to have subnodes
and probe each of them automatically with devm_platform_populate(). If
the node as no child, the probe function for NSRs will still be called
'manually'.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 85 +++++++++++++++++++++++++++++++++--------
 1 file changed, 70 insertions(+), 15 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index c919110dcee5..1d3cd112619c 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -44,6 +44,7 @@ struct mvebu_icu {
 	struct irq_chip irq_chip;
 	struct regmap *regmap;
 	struct device *dev;
+	bool legacy_bindings;
 };
 
 struct mvebu_icu_irq_data {
@@ -52,6 +53,27 @@ struct mvebu_icu_irq_data {
 	unsigned int type;
 };
 
+static struct mvebu_icu *mvebu_dev_get_drvdata(struct platform_device *pdev)
+{
+	struct mvebu_icu *icu;
+
+	icu = dev_get_drvdata(&pdev->dev);
+	if (icu) {
+		/* Legacy bindings: get the device data */
+		if (!icu->legacy_bindings)
+			return ERR_PTR(-EINVAL);
+	} else {
+		/* New bindings: get the parent device (ICU) data */
+		icu = dev_get_drvdata(pdev->dev.parent);
+		if (!icu)
+			return ERR_PTR(-ENODEV);
+		if (icu->legacy_bindings)
+			return ERR_PTR(-EINVAL);
+	}
+
+	return icu;
+}
+
 static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
 {
 	struct irq_data *d = irq_get_irq_data(desc->irq);
@@ -94,31 +116,35 @@ mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
 			       unsigned long *hwirq, unsigned int *type)
 {
 	struct mvebu_icu *icu = platform_msi_get_host_data(d);
-	unsigned int icu_group;
+	unsigned int param_count = icu->legacy_bindings ? 3 : 2;
 
 	/* Check the count of the parameters in dt */
-	if (WARN_ON(fwspec->param_count < 3)) {
+	if (WARN_ON(fwspec->param_count != param_count)) {
 		dev_err(icu->dev, "wrong ICU parameter count %d\n",
 			fwspec->param_count);
 		return -EINVAL;
 	}
 
-	/* Only ICU group type is handled */
-	icu_group = fwspec->param[0];
-	if (icu_group != ICU_GRP_NSR && icu_group != ICU_GRP_SR &&
-	    icu_group != ICU_GRP_SEI && icu_group != ICU_GRP_REI) {
-		dev_err(icu->dev, "wrong ICU group type %x\n", icu_group);
-		return -EINVAL;
+	if (icu->legacy_bindings) {
+		*hwirq = fwspec->param[1];
+		*type = fwspec->param[2];
+		if (fwspec->param[0] != ICU_GRP_NSR) {
+			dev_err(icu->dev, "wrong ICU group type %x\n",
+				fwspec->param[0]);
+			return -EINVAL;
+		}
+	} else {
+		*hwirq = fwspec->param[0];
+		*type = fwspec->param[1];
 	}
 
-	*hwirq = fwspec->param[1];
 	if (*hwirq >= ICU_MAX_IRQS) {
 		dev_err(icu->dev, "invalid interrupt number %ld\n", *hwirq);
 		return -EINVAL;
 	}
 
 	/* Mask the type to prevent wrong DT configuration */
-	*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+	*type &= IRQ_TYPE_SENSE_MASK;
 
 	return 0;
 }
@@ -144,7 +170,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 		goto free_irqd;
 	}
 
-	icu_irqd->icu_group = fwspec->param[0];
+	if (icu->legacy_bindings)
+		icu_irqd->icu_group = fwspec->param[0];
+	else
+		icu_irqd->icu_group = ICU_GRP_NSR;
 	icu_irqd->icu = icu;
 
 	err = platform_msi_domain_alloc(domain, virq, nr_irqs);
@@ -200,9 +229,9 @@ static int mvebu_icu_nsr_probe(struct platform_device *pdev)
 	phys_addr_t set, clr;
 	int ret;
 
-	icu = dev_get_drvdata(&pdev->dev);
-	if (!icu)
-		return -ENODEV;
+	icu = mvebu_dev_get_drvdata(pdev);
+	if (IS_ERR(icu))
+		return PTR_ERR(icu);
 
 	pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, pdev->dev.of_node,
 						 DOMAIN_BUS_PLATFORM_MSI);
@@ -235,6 +264,20 @@ static int mvebu_icu_nsr_probe(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id mvebu_icu_nsr_of_match[] = {
+	{ .compatible = "marvell,cp110-icu-nsr", },
+	{},
+};
+
+static struct platform_driver mvebu_icu_nsr_driver = {
+	.probe  = mvebu_icu_nsr_probe,
+	.driver = {
+		.name = "mvebu-icu-nsr",
+		.of_match_table = mvebu_icu_nsr_of_match,
+	},
+};
+builtin_platform_driver(mvebu_icu_nsr_driver);
+
 static int mvebu_icu_probe(struct platform_device *pdev)
 {
 	struct mvebu_icu *icu;
@@ -262,6 +305,15 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 	if (!icu->irq_chip.name)
 		return -ENOMEM;
 
+	/*
+	 * Legacy bindings: ICU is one node with one MSI parent: force manually
+	 *                  the probe of the NSR interrupts side.
+	 * New bindings: ICU node has children, one per interrupt controller
+	 *               having its own MSI parent: call platform_populate().
+	 */
+	if (!of_get_child_count(pdev->dev.of_node))
+		icu->legacy_bindings = true;
+
 	icu->irq_chip.irq_mask = irq_chip_mask_parent;
 	icu->irq_chip.irq_unmask = irq_chip_unmask_parent;
 	icu->irq_chip.irq_eoi = irq_chip_eoi_parent;
@@ -286,7 +338,10 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, icu);
 
-	return mvebu_icu_nsr_probe(pdev);
+	if (icu->legacy_bindings)
+		return mvebu_icu_nsr_probe(pdev);
+	else
+		return devm_of_platform_populate(&pdev->dev);
 }
 
 static const struct of_device_id mvebu_icu_of_match[] = {
-- 
2.14.1

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

* [PATCH 10/17] irqchip/irq-mvebu-sei: add new driver for Marvell SEI
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

This is a cascaded interrupt controller in the AP806 GIC that collapses
SEIs (System Error Interrupt) coming from the AP and the CPs (through
the ICU).

The SEI handles up to 64 interrupts. The first 21 interrupts are wired
and come from the AP. The next 43 interrupts are from the CPs and are
triggered through MSI messages. To handle this complexity, the driver
has to declare to the upper layer: one IRQ domain for the wired
interrupts, one IRQ domain for the MSIs; and acts as a MSI server
('parent') by declaring an MSI domain.

Suggested-by: Haim Boot <hayim@marvell.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/Kconfig         |   3 +
 drivers/irqchip/Makefile        |   1 +
 drivers/irqchip/irq-mvebu-sei.c | 449 ++++++++++++++++++++++++++++++++++++++++
 drivers/irqchip/irq-mvebu-sei.h |  12 ++
 4 files changed, 465 insertions(+)
 create mode 100644 drivers/irqchip/irq-mvebu-sei.c
 create mode 100644 drivers/irqchip/irq-mvebu-sei.h

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index e9233db16e03..922e2a919cf3 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -310,6 +310,9 @@ config MVEBU_ODMI
 config MVEBU_PIC
 	bool
 
+config MVEBU_SEI
+        bool
+
 config LS_SCFG_MSI
 	def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
 	depends on PCI && PCI_MSI
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 5ed465ab1c76..6b5b75cb4694 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
 obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
 obj-$(CONFIG_MSCC_OCELOT_IRQ)		+= irq-mscc-ocelot.o
 obj-$(CONFIG_MVEBU_GICP)		+= irq-mvebu-gicp.o
+obj-$(CONFIG_MVEBU_SEI)			+= irq-mvebu-sei.o
 obj-$(CONFIG_MVEBU_ICU)			+= irq-mvebu-icu.o
 obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
 obj-$(CONFIG_MVEBU_PIC)			+= irq-mvebu-pic.o
diff --git a/drivers/irqchip/irq-mvebu-sei.c b/drivers/irqchip/irq-mvebu-sei.c
new file mode 100644
index 000000000000..5c12c74e3f09
--- /dev/null
+++ b/drivers/irqchip/irq-mvebu-sei.c
@@ -0,0 +1,449 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
+
+#define pr_fmt(fmt) "mvebu-sei: " fmt
+
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/msi.h>
+#include <linux/platform_device.h>
+#include <linux/irqchip.h>
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#define GICP_SET_SEI_OFFSET	0x30
+#define GICP_CLR_SEI_OFFSET	GICP_SET_SEI_OFFSET
+
+/* Cause register */
+#define GICP_SECR(idx)		(0x0  + (idx * 0x4))
+/* Mask register */
+#define GICP_SEMR(idx)		(0x20 + (idx * 0x4))
+
+#define SEI_IRQ_NB_PER_REG	32
+#define SEI_IRQ_REG_NB		2
+#define SEI_IRQ_NB		(SEI_IRQ_NB_PER_REG * SEI_IRQ_REG_NB)
+#define SEI_IRQ_REG_IDX(irq_id)	(irq_id / SEI_IRQ_NB_PER_REG)
+#define SEI_IRQ_REG_BIT(irq_id)	(irq_id % SEI_IRQ_NB_PER_REG)
+
+struct mvebu_sei_interrupt_range {
+	u32 first;
+	u32 number;
+};
+
+struct mvebu_sei {
+	struct device *dev;
+	void __iomem *base;
+	struct resource *res;
+	struct irq_domain *ap_domain;
+	struct irq_domain *cp_domain;
+	struct mvebu_sei_interrupt_range ap_interrupts;
+	struct mvebu_sei_interrupt_range cp_interrupts;
+	/* Lock on MSI allocations/releases */
+	spinlock_t cp_msi_lock;
+	DECLARE_BITMAP(cp_msi_bitmap, SEI_IRQ_NB);
+};
+
+static int mvebu_sei_domain_to_sei_irq(struct mvebu_sei *sei,
+				       struct irq_domain *domain,
+				       irq_hw_number_t hwirq)
+{
+	if (domain == sei->ap_domain)
+		return sei->ap_interrupts.first + hwirq;
+	else
+		return sei->cp_interrupts.first + hwirq;
+}
+
+static void mvebu_sei_reset(struct mvebu_sei *sei)
+{
+	u32 reg_idx;
+
+	for (reg_idx = 0; reg_idx < SEI_IRQ_REG_NB; reg_idx++) {
+		/* Clear all cause bits */
+		writel(0xFFFFFFFF, sei->base + GICP_SECR(reg_idx));
+		/* Enable all interrupts */
+		writel(0, sei->base + GICP_SEMR(reg_idx));
+	}
+}
+
+int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
+			    phys_addr_t *clr)
+{
+	struct platform_device *pdev;
+	struct mvebu_sei *sei;
+
+	pdev = of_find_device_by_node(dn->parent);
+	if (!pdev)
+		return -ENODEV;
+
+	sei = platform_get_drvdata(pdev);
+	if (!sei)
+		return -ENODEV;
+
+	*set = (phys_addr_t)(sei->res->start + GICP_SET_SEI_OFFSET);
+	*clr = (phys_addr_t)(sei->res->start + GICP_CLR_SEI_OFFSET);
+
+	return 0;
+}
+
+static void mvebu_sei_mask_irq(struct irq_data *d)
+{
+	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
+	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
+	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
+	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
+	u32 reg;
+
+	/* 1 disables the interrupt */
+	reg =  readl(sei->base + GICP_SEMR(reg_idx));
+	writel(reg | irq_mask, sei->base + GICP_SEMR(reg_idx));
+}
+
+static void mvebu_sei_unmask_irq(struct irq_data *d)
+{
+	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
+	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
+	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
+	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
+	u32 reg;
+
+	/* 0 enables the interrupt */
+	reg = readl(sei->base + GICP_SEMR(reg_idx));
+	writel(reg & ~irq_mask, sei->base + GICP_SEMR(reg_idx));
+}
+
+static void mvebu_sei_compose_msi_msg(struct irq_data *data,
+				      struct msi_msg *msg)
+{
+	struct mvebu_sei *sei = data->chip_data;
+	phys_addr_t set = sei->res->start + GICP_SET_SEI_OFFSET;
+
+	msg->data = mvebu_sei_domain_to_sei_irq(sei, data->domain, data->hwirq);
+	msg->address_lo = lower_32_bits(set);
+	msg->address_hi = upper_32_bits(set);
+}
+
+static struct irq_chip mvebu_sei_ap_wired_irq_chip = {
+	.name			= "AP wired SEI",
+	.irq_mask		= mvebu_sei_mask_irq,
+	.irq_unmask		= mvebu_sei_unmask_irq,
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+	.irq_set_type		= irq_chip_set_type_parent,
+};
+
+static struct irq_chip mvebu_sei_cp_msi_irq_chip = {
+	.name			= "CP MSI SEI",
+	.irq_mask		= mvebu_sei_mask_irq,
+	.irq_unmask		= mvebu_sei_unmask_irq,
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+	.irq_set_type		= irq_chip_set_type_parent,
+	.irq_compose_msi_msg	= mvebu_sei_compose_msi_msg,
+};
+
+static int mvebu_sei_irq_domain_alloc(struct irq_domain *domain,
+				      unsigned int virq, unsigned int nr_irqs,
+				      void *args)
+{
+	struct mvebu_sei *sei = domain->host_data;
+	struct irq_fwspec *fwspec = args;
+	struct irq_chip *irq_chip;
+	int sei_hwirq, hwirq;
+	int ret;
+
+	/* Software only supports single allocations for now */
+	if (nr_irqs != 1)
+		return -ENOTSUPP;
+
+	if (domain == sei->ap_domain) {
+		irq_chip = &mvebu_sei_ap_wired_irq_chip;
+		hwirq = fwspec->param[0];
+	} else {
+		irq_chip = &mvebu_sei_cp_msi_irq_chip;
+		spin_lock(&sei->cp_msi_lock);
+		hwirq = bitmap_find_free_region(sei->cp_msi_bitmap, SEI_IRQ_NB,
+						0);
+		spin_unlock(&sei->cp_msi_lock);
+		if (hwirq < 0)
+			return -ENOSPC;
+	}
+
+	sei_hwirq = mvebu_sei_domain_to_sei_irq(sei, domain, hwirq);
+
+	fwspec->fwnode = domain->parent->fwnode;
+	fwspec->param_count = 3;
+	fwspec->param[0] = GIC_SPI;
+	fwspec->param[1] = sei_hwirq;
+	fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
+
+	ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, fwspec);
+	if (ret)
+		goto release_region;
+
+	ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, irq_chip, sei);
+	if (ret)
+		goto free_irq_parents;
+
+	return 0;
+
+free_irq_parents:
+	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+release_region:
+	if (domain == sei->cp_domain) {
+		spin_lock(&sei->cp_msi_lock);
+		bitmap_release_region(sei->cp_msi_bitmap, hwirq, 0);
+		spin_unlock(&sei->cp_msi_lock);
+	}
+
+	return ret;
+}
+
+static void mvebu_sei_irq_domain_free(struct irq_domain *domain,
+				      unsigned int virq, unsigned int nr_irqs)
+{
+	struct mvebu_sei *sei = domain->host_data;
+	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+	u32 irq_nb = sei->ap_interrupts.number + sei->cp_interrupts.number;
+
+	if (nr_irqs != 1 || d->hwirq >= irq_nb) {
+		dev_err(sei->dev, "Invalid hwirq %lu\n", d->hwirq);
+		return;
+	}
+
+	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+
+	spin_lock(&sei->cp_msi_lock);
+	bitmap_release_region(sei->cp_msi_bitmap, d->hwirq, 0);
+	spin_unlock(&sei->cp_msi_lock);
+}
+
+static const struct irq_domain_ops mvebu_sei_ap_domain_ops = {
+	.xlate = irq_domain_xlate_onecell,
+	.alloc = mvebu_sei_irq_domain_alloc,
+	.free = mvebu_sei_irq_domain_free,
+};
+
+static const struct irq_domain_ops mvebu_sei_cp_domain_ops = {
+	.xlate = irq_domain_xlate_twocell,
+	.alloc = mvebu_sei_irq_domain_alloc,
+	.free = mvebu_sei_irq_domain_free,
+};
+
+static struct irq_chip mvebu_sei_msi_irq_chip = {
+	.name		= "SEI",
+	.irq_set_type	= irq_chip_set_type_parent,
+};
+
+static struct msi_domain_ops mvebu_sei_msi_ops = {
+};
+
+static struct msi_domain_info mvebu_sei_msi_domain_info = {
+	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
+	.ops	= &mvebu_sei_msi_ops,
+	.chip	= &mvebu_sei_msi_irq_chip,
+};
+
+static void mvebu_sei_handle_cascade_irq(struct irq_desc *desc)
+{
+	struct mvebu_sei *sei = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	unsigned long irqmap, irq_bit;
+	u32 reg_idx, virq, irqn;
+
+	chained_irq_enter(chip, desc);
+
+	/* Read both SEI cause registers (64 bits) */
+	for (reg_idx = 0; reg_idx < SEI_IRQ_REG_NB; reg_idx++) {
+		irqmap = readl_relaxed(sei->base + GICP_SECR(reg_idx));
+
+		/* Call handler for each set bit */
+		for_each_set_bit(irq_bit, &irqmap, SEI_IRQ_NB_PER_REG) {
+			/* Cause Register gives the SEI number */
+			irqn = irq_bit + reg_idx * SEI_IRQ_NB_PER_REG;
+			/*
+			 * Finding Linux mapping (virq) needs the right domain
+			 * and the relative hwirq (which start at 0 in both
+			 * cases, while irqn is relative to all SEI interrupts).
+			 */
+			if (irqn < sei->ap_interrupts.number) {
+				virq = irq_find_mapping(sei->ap_domain, irqn);
+			} else {
+				irqn -= sei->ap_interrupts.number;
+				virq = irq_find_mapping(sei->cp_domain, irqn);
+			}
+
+			/* Call IRQ handler */
+			generic_handle_irq(virq);
+		}
+
+		/* Clear interrupt indication by writing 1 to it */
+		writel(irqmap, sei->base + GICP_SECR(reg_idx));
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static int mvebu_sei_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node, *parent, *child;
+	struct irq_domain *parent_domain, *plat_domain;
+	struct mvebu_sei *sei;
+	const __be32 *property;
+	u32 top_level_spi, size;
+	int ret;
+
+	sei = devm_kzalloc(&pdev->dev, sizeof(*sei), GFP_KERNEL);
+	if (!sei)
+		return -ENOMEM;
+
+	sei->dev = &pdev->dev;
+
+	spin_lock_init(&sei->cp_msi_lock);
+
+	sei->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!sei->res) {
+		dev_err(sei->dev, "Failed to retrieve SEI resource\n");
+		return -ENODEV;
+	}
+
+	sei->base = devm_ioremap(sei->dev, sei->res->start,
+				 resource_size(sei->res));
+	if (!sei->base) {
+		dev_err(sei->dev, "Failed to remap SEI resource\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Reserve the single (top-level) parent SPI IRQ from which all the
+	 * interrupts handled by this driver will be signaled.
+	 */
+	top_level_spi = irq_of_parse_and_map(node, 0);
+	if (top_level_spi <= 0) {
+		dev_err(sei->dev, "Failed to retrieve top-level SPI IRQ\n");
+		return -ENODEV;
+	}
+
+	irq_set_chained_handler(top_level_spi, mvebu_sei_handle_cascade_irq);
+	irq_set_handler_data(top_level_spi, sei);
+
+	/*
+	 * SEIs in the range [ 0; 20] are wired and come from the AP.
+	 * SEIs in the range [21; 63] are CP SEI and are triggered through MSIs.
+	 *
+	 * Each SEI 'domain' is represented as a subnode.
+	 */
+
+	/* Get a reference to the parent domain to create a hierarchy */
+	parent = of_irq_find_parent(node);
+	if (!parent) {
+		dev_err(sei->dev, "Failed to find parent IRQ node\n");
+		ret = -ENODEV;
+		goto dispose_irq;
+	}
+
+	parent_domain = irq_find_host(parent);
+	if (!parent_domain) {
+		dev_err(sei->dev, "Failed to find parent IRQ domain\n");
+		ret = -ENODEV;
+		goto dispose_irq;
+	}
+
+	/* Create the 'wired' hierarchy */
+	child = of_find_node_by_name(node, "sei-wired-controller");
+	if (!child) {
+		dev_err(sei->dev, "Missing 'sei-wired-controller' subnode\n");
+		ret = -ENODEV;
+		goto dispose_irq;
+	}
+
+	property = of_get_property(child, "reg", &size);
+	if (!property || size != (2 * sizeof(u32))) {
+		dev_err(sei->dev, "Missing subnode 'reg' property\n");
+		ret = -ENODEV;
+		goto dispose_irq;
+	}
+
+	sei->ap_interrupts.first = be32_to_cpu(property[0]);
+	sei->ap_interrupts.number = be32_to_cpu(property[1]);
+	sei->ap_domain = irq_domain_create_hierarchy(parent_domain, 0,
+						     sei->ap_interrupts.number,
+						     of_node_to_fwnode(child),
+						     &mvebu_sei_ap_domain_ops,
+						     sei);
+	if (!sei->ap_domain) {
+		dev_err(sei->dev, "Failed to create AP IRQ domain\n");
+		ret = -ENOMEM;
+		goto dispose_irq;
+	}
+
+	/* Create the 'MSI' hierarchy */
+	child = of_find_node_by_name(node, "sei-msi-controller");
+	if (!child) {
+		dev_err(sei->dev, "Missing 'sei-msi-controller' subnode\n");
+		ret = -ENODEV;
+		goto remove_ap_domain;
+	}
+
+	property = of_get_property(child, "reg", &size);
+	if (!property || size != (2 * sizeof(u32))) {
+		dev_err(sei->dev, "Missing subnode 'reg' property\n");
+		ret = -ENODEV;
+		goto remove_ap_domain;
+	}
+
+	sei->cp_interrupts.first = be32_to_cpu(property[0]);
+	sei->cp_interrupts.number = be32_to_cpu(property[1]);
+	sei->cp_domain = irq_domain_create_hierarchy(parent_domain, 0,
+						     sei->cp_interrupts.number,
+						     of_node_to_fwnode(child),
+						     &mvebu_sei_cp_domain_ops,
+						     sei);
+	if (!sei->cp_domain) {
+		pr_err("Failed to create CPs IRQ domain\n");
+		ret = -ENOMEM;
+		goto remove_ap_domain;
+	}
+
+	plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(child),
+						     &mvebu_sei_msi_domain_info,
+						     sei->cp_domain);
+	if (!plat_domain) {
+		pr_err("Failed to create CPs MSI domain\n");
+		ret = -ENOMEM;
+		goto remove_cp_domain;
+	}
+
+	platform_set_drvdata(pdev, sei);
+
+	mvebu_sei_reset(sei);
+
+	return 0;
+
+remove_cp_domain:
+	irq_domain_remove(sei->cp_domain);
+remove_ap_domain:
+	irq_domain_remove(sei->ap_domain);
+dispose_irq:
+	irq_dispose_mapping(top_level_spi);
+
+	return ret;
+}
+
+static const struct of_device_id mvebu_sei_of_match[] = {
+	{ .compatible = "marvell,armada-8k-sei", },
+	{},
+};
+
+static struct platform_driver mvebu_sei_driver = {
+	.probe  = mvebu_sei_probe,
+	.driver = {
+		.name = "mvebu-sei",
+		.of_match_table = mvebu_sei_of_match,
+	},
+};
+builtin_platform_driver(mvebu_sei_driver);
diff --git a/drivers/irqchip/irq-mvebu-sei.h b/drivers/irqchip/irq-mvebu-sei.h
new file mode 100644
index 000000000000..f0c12a441923
--- /dev/null
+++ b/drivers/irqchip/irq-mvebu-sei.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MVEBU_SEI_H__
+#define __MVEBU_SEI_H__
+
+#include <linux/types.h>
+
+struct device_node;
+
+int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
+			    phys_addr_t *clr);
+
+#endif /* __MVEBU_SEI_H__ */
-- 
2.14.1

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

* [PATCH 10/17] irqchip/irq-mvebu-sei: add new driver for Marvell SEI
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

This is a cascaded interrupt controller in the AP806 GIC that collapses
SEIs (System Error Interrupt) coming from the AP and the CPs (through
the ICU).

The SEI handles up to 64 interrupts. The first 21 interrupts are wired
and come from the AP. The next 43 interrupts are from the CPs and are
triggered through MSI messages. To handle this complexity, the driver
has to declare to the upper layer: one IRQ domain for the wired
interrupts, one IRQ domain for the MSIs; and acts as a MSI server
('parent') by declaring an MSI domain.

Suggested-by: Haim Boot <hayim@marvell.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/Kconfig         |   3 +
 drivers/irqchip/Makefile        |   1 +
 drivers/irqchip/irq-mvebu-sei.c | 449 ++++++++++++++++++++++++++++++++++++++++
 drivers/irqchip/irq-mvebu-sei.h |  12 ++
 4 files changed, 465 insertions(+)
 create mode 100644 drivers/irqchip/irq-mvebu-sei.c
 create mode 100644 drivers/irqchip/irq-mvebu-sei.h

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index e9233db16e03..922e2a919cf3 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -310,6 +310,9 @@ config MVEBU_ODMI
 config MVEBU_PIC
 	bool
 
+config MVEBU_SEI
+        bool
+
 config LS_SCFG_MSI
 	def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
 	depends on PCI && PCI_MSI
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 5ed465ab1c76..6b5b75cb4694 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
 obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
 obj-$(CONFIG_MSCC_OCELOT_IRQ)		+= irq-mscc-ocelot.o
 obj-$(CONFIG_MVEBU_GICP)		+= irq-mvebu-gicp.o
+obj-$(CONFIG_MVEBU_SEI)			+= irq-mvebu-sei.o
 obj-$(CONFIG_MVEBU_ICU)			+= irq-mvebu-icu.o
 obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
 obj-$(CONFIG_MVEBU_PIC)			+= irq-mvebu-pic.o
diff --git a/drivers/irqchip/irq-mvebu-sei.c b/drivers/irqchip/irq-mvebu-sei.c
new file mode 100644
index 000000000000..5c12c74e3f09
--- /dev/null
+++ b/drivers/irqchip/irq-mvebu-sei.c
@@ -0,0 +1,449 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
+
+#define pr_fmt(fmt) "mvebu-sei: " fmt
+
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/msi.h>
+#include <linux/platform_device.h>
+#include <linux/irqchip.h>
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#define GICP_SET_SEI_OFFSET	0x30
+#define GICP_CLR_SEI_OFFSET	GICP_SET_SEI_OFFSET
+
+/* Cause register */
+#define GICP_SECR(idx)		(0x0  + (idx * 0x4))
+/* Mask register */
+#define GICP_SEMR(idx)		(0x20 + (idx * 0x4))
+
+#define SEI_IRQ_NB_PER_REG	32
+#define SEI_IRQ_REG_NB		2
+#define SEI_IRQ_NB		(SEI_IRQ_NB_PER_REG * SEI_IRQ_REG_NB)
+#define SEI_IRQ_REG_IDX(irq_id)	(irq_id / SEI_IRQ_NB_PER_REG)
+#define SEI_IRQ_REG_BIT(irq_id)	(irq_id % SEI_IRQ_NB_PER_REG)
+
+struct mvebu_sei_interrupt_range {
+	u32 first;
+	u32 number;
+};
+
+struct mvebu_sei {
+	struct device *dev;
+	void __iomem *base;
+	struct resource *res;
+	struct irq_domain *ap_domain;
+	struct irq_domain *cp_domain;
+	struct mvebu_sei_interrupt_range ap_interrupts;
+	struct mvebu_sei_interrupt_range cp_interrupts;
+	/* Lock on MSI allocations/releases */
+	spinlock_t cp_msi_lock;
+	DECLARE_BITMAP(cp_msi_bitmap, SEI_IRQ_NB);
+};
+
+static int mvebu_sei_domain_to_sei_irq(struct mvebu_sei *sei,
+				       struct irq_domain *domain,
+				       irq_hw_number_t hwirq)
+{
+	if (domain == sei->ap_domain)
+		return sei->ap_interrupts.first + hwirq;
+	else
+		return sei->cp_interrupts.first + hwirq;
+}
+
+static void mvebu_sei_reset(struct mvebu_sei *sei)
+{
+	u32 reg_idx;
+
+	for (reg_idx = 0; reg_idx < SEI_IRQ_REG_NB; reg_idx++) {
+		/* Clear all cause bits */
+		writel(0xFFFFFFFF, sei->base + GICP_SECR(reg_idx));
+		/* Enable all interrupts */
+		writel(0, sei->base + GICP_SEMR(reg_idx));
+	}
+}
+
+int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
+			    phys_addr_t *clr)
+{
+	struct platform_device *pdev;
+	struct mvebu_sei *sei;
+
+	pdev = of_find_device_by_node(dn->parent);
+	if (!pdev)
+		return -ENODEV;
+
+	sei = platform_get_drvdata(pdev);
+	if (!sei)
+		return -ENODEV;
+
+	*set = (phys_addr_t)(sei->res->start + GICP_SET_SEI_OFFSET);
+	*clr = (phys_addr_t)(sei->res->start + GICP_CLR_SEI_OFFSET);
+
+	return 0;
+}
+
+static void mvebu_sei_mask_irq(struct irq_data *d)
+{
+	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
+	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
+	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
+	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
+	u32 reg;
+
+	/* 1 disables the interrupt */
+	reg =  readl(sei->base + GICP_SEMR(reg_idx));
+	writel(reg | irq_mask, sei->base + GICP_SEMR(reg_idx));
+}
+
+static void mvebu_sei_unmask_irq(struct irq_data *d)
+{
+	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
+	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
+	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
+	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
+	u32 reg;
+
+	/* 0 enables the interrupt */
+	reg = readl(sei->base + GICP_SEMR(reg_idx));
+	writel(reg & ~irq_mask, sei->base + GICP_SEMR(reg_idx));
+}
+
+static void mvebu_sei_compose_msi_msg(struct irq_data *data,
+				      struct msi_msg *msg)
+{
+	struct mvebu_sei *sei = data->chip_data;
+	phys_addr_t set = sei->res->start + GICP_SET_SEI_OFFSET;
+
+	msg->data = mvebu_sei_domain_to_sei_irq(sei, data->domain, data->hwirq);
+	msg->address_lo = lower_32_bits(set);
+	msg->address_hi = upper_32_bits(set);
+}
+
+static struct irq_chip mvebu_sei_ap_wired_irq_chip = {
+	.name			= "AP wired SEI",
+	.irq_mask		= mvebu_sei_mask_irq,
+	.irq_unmask		= mvebu_sei_unmask_irq,
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+	.irq_set_type		= irq_chip_set_type_parent,
+};
+
+static struct irq_chip mvebu_sei_cp_msi_irq_chip = {
+	.name			= "CP MSI SEI",
+	.irq_mask		= mvebu_sei_mask_irq,
+	.irq_unmask		= mvebu_sei_unmask_irq,
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+	.irq_set_type		= irq_chip_set_type_parent,
+	.irq_compose_msi_msg	= mvebu_sei_compose_msi_msg,
+};
+
+static int mvebu_sei_irq_domain_alloc(struct irq_domain *domain,
+				      unsigned int virq, unsigned int nr_irqs,
+				      void *args)
+{
+	struct mvebu_sei *sei = domain->host_data;
+	struct irq_fwspec *fwspec = args;
+	struct irq_chip *irq_chip;
+	int sei_hwirq, hwirq;
+	int ret;
+
+	/* Software only supports single allocations for now */
+	if (nr_irqs != 1)
+		return -ENOTSUPP;
+
+	if (domain == sei->ap_domain) {
+		irq_chip = &mvebu_sei_ap_wired_irq_chip;
+		hwirq = fwspec->param[0];
+	} else {
+		irq_chip = &mvebu_sei_cp_msi_irq_chip;
+		spin_lock(&sei->cp_msi_lock);
+		hwirq = bitmap_find_free_region(sei->cp_msi_bitmap, SEI_IRQ_NB,
+						0);
+		spin_unlock(&sei->cp_msi_lock);
+		if (hwirq < 0)
+			return -ENOSPC;
+	}
+
+	sei_hwirq = mvebu_sei_domain_to_sei_irq(sei, domain, hwirq);
+
+	fwspec->fwnode = domain->parent->fwnode;
+	fwspec->param_count = 3;
+	fwspec->param[0] = GIC_SPI;
+	fwspec->param[1] = sei_hwirq;
+	fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
+
+	ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, fwspec);
+	if (ret)
+		goto release_region;
+
+	ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, irq_chip, sei);
+	if (ret)
+		goto free_irq_parents;
+
+	return 0;
+
+free_irq_parents:
+	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+release_region:
+	if (domain == sei->cp_domain) {
+		spin_lock(&sei->cp_msi_lock);
+		bitmap_release_region(sei->cp_msi_bitmap, hwirq, 0);
+		spin_unlock(&sei->cp_msi_lock);
+	}
+
+	return ret;
+}
+
+static void mvebu_sei_irq_domain_free(struct irq_domain *domain,
+				      unsigned int virq, unsigned int nr_irqs)
+{
+	struct mvebu_sei *sei = domain->host_data;
+	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+	u32 irq_nb = sei->ap_interrupts.number + sei->cp_interrupts.number;
+
+	if (nr_irqs != 1 || d->hwirq >= irq_nb) {
+		dev_err(sei->dev, "Invalid hwirq %lu\n", d->hwirq);
+		return;
+	}
+
+	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+
+	spin_lock(&sei->cp_msi_lock);
+	bitmap_release_region(sei->cp_msi_bitmap, d->hwirq, 0);
+	spin_unlock(&sei->cp_msi_lock);
+}
+
+static const struct irq_domain_ops mvebu_sei_ap_domain_ops = {
+	.xlate = irq_domain_xlate_onecell,
+	.alloc = mvebu_sei_irq_domain_alloc,
+	.free = mvebu_sei_irq_domain_free,
+};
+
+static const struct irq_domain_ops mvebu_sei_cp_domain_ops = {
+	.xlate = irq_domain_xlate_twocell,
+	.alloc = mvebu_sei_irq_domain_alloc,
+	.free = mvebu_sei_irq_domain_free,
+};
+
+static struct irq_chip mvebu_sei_msi_irq_chip = {
+	.name		= "SEI",
+	.irq_set_type	= irq_chip_set_type_parent,
+};
+
+static struct msi_domain_ops mvebu_sei_msi_ops = {
+};
+
+static struct msi_domain_info mvebu_sei_msi_domain_info = {
+	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
+	.ops	= &mvebu_sei_msi_ops,
+	.chip	= &mvebu_sei_msi_irq_chip,
+};
+
+static void mvebu_sei_handle_cascade_irq(struct irq_desc *desc)
+{
+	struct mvebu_sei *sei = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	unsigned long irqmap, irq_bit;
+	u32 reg_idx, virq, irqn;
+
+	chained_irq_enter(chip, desc);
+
+	/* Read both SEI cause registers (64 bits) */
+	for (reg_idx = 0; reg_idx < SEI_IRQ_REG_NB; reg_idx++) {
+		irqmap = readl_relaxed(sei->base + GICP_SECR(reg_idx));
+
+		/* Call handler for each set bit */
+		for_each_set_bit(irq_bit, &irqmap, SEI_IRQ_NB_PER_REG) {
+			/* Cause Register gives the SEI number */
+			irqn = irq_bit + reg_idx * SEI_IRQ_NB_PER_REG;
+			/*
+			 * Finding Linux mapping (virq) needs the right domain
+			 * and the relative hwirq (which start at 0 in both
+			 * cases, while irqn is relative to all SEI interrupts).
+			 */
+			if (irqn < sei->ap_interrupts.number) {
+				virq = irq_find_mapping(sei->ap_domain, irqn);
+			} else {
+				irqn -= sei->ap_interrupts.number;
+				virq = irq_find_mapping(sei->cp_domain, irqn);
+			}
+
+			/* Call IRQ handler */
+			generic_handle_irq(virq);
+		}
+
+		/* Clear interrupt indication by writing 1 to it */
+		writel(irqmap, sei->base + GICP_SECR(reg_idx));
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static int mvebu_sei_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node, *parent, *child;
+	struct irq_domain *parent_domain, *plat_domain;
+	struct mvebu_sei *sei;
+	const __be32 *property;
+	u32 top_level_spi, size;
+	int ret;
+
+	sei = devm_kzalloc(&pdev->dev, sizeof(*sei), GFP_KERNEL);
+	if (!sei)
+		return -ENOMEM;
+
+	sei->dev = &pdev->dev;
+
+	spin_lock_init(&sei->cp_msi_lock);
+
+	sei->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!sei->res) {
+		dev_err(sei->dev, "Failed to retrieve SEI resource\n");
+		return -ENODEV;
+	}
+
+	sei->base = devm_ioremap(sei->dev, sei->res->start,
+				 resource_size(sei->res));
+	if (!sei->base) {
+		dev_err(sei->dev, "Failed to remap SEI resource\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Reserve the single (top-level) parent SPI IRQ from which all the
+	 * interrupts handled by this driver will be signaled.
+	 */
+	top_level_spi = irq_of_parse_and_map(node, 0);
+	if (top_level_spi <= 0) {
+		dev_err(sei->dev, "Failed to retrieve top-level SPI IRQ\n");
+		return -ENODEV;
+	}
+
+	irq_set_chained_handler(top_level_spi, mvebu_sei_handle_cascade_irq);
+	irq_set_handler_data(top_level_spi, sei);
+
+	/*
+	 * SEIs in the range [ 0; 20] are wired and come from the AP.
+	 * SEIs in the range [21; 63] are CP SEI and are triggered through MSIs.
+	 *
+	 * Each SEI 'domain' is represented as a subnode.
+	 */
+
+	/* Get a reference to the parent domain to create a hierarchy */
+	parent = of_irq_find_parent(node);
+	if (!parent) {
+		dev_err(sei->dev, "Failed to find parent IRQ node\n");
+		ret = -ENODEV;
+		goto dispose_irq;
+	}
+
+	parent_domain = irq_find_host(parent);
+	if (!parent_domain) {
+		dev_err(sei->dev, "Failed to find parent IRQ domain\n");
+		ret = -ENODEV;
+		goto dispose_irq;
+	}
+
+	/* Create the 'wired' hierarchy */
+	child = of_find_node_by_name(node, "sei-wired-controller");
+	if (!child) {
+		dev_err(sei->dev, "Missing 'sei-wired-controller' subnode\n");
+		ret = -ENODEV;
+		goto dispose_irq;
+	}
+
+	property = of_get_property(child, "reg", &size);
+	if (!property || size != (2 * sizeof(u32))) {
+		dev_err(sei->dev, "Missing subnode 'reg' property\n");
+		ret = -ENODEV;
+		goto dispose_irq;
+	}
+
+	sei->ap_interrupts.first = be32_to_cpu(property[0]);
+	sei->ap_interrupts.number = be32_to_cpu(property[1]);
+	sei->ap_domain = irq_domain_create_hierarchy(parent_domain, 0,
+						     sei->ap_interrupts.number,
+						     of_node_to_fwnode(child),
+						     &mvebu_sei_ap_domain_ops,
+						     sei);
+	if (!sei->ap_domain) {
+		dev_err(sei->dev, "Failed to create AP IRQ domain\n");
+		ret = -ENOMEM;
+		goto dispose_irq;
+	}
+
+	/* Create the 'MSI' hierarchy */
+	child = of_find_node_by_name(node, "sei-msi-controller");
+	if (!child) {
+		dev_err(sei->dev, "Missing 'sei-msi-controller' subnode\n");
+		ret = -ENODEV;
+		goto remove_ap_domain;
+	}
+
+	property = of_get_property(child, "reg", &size);
+	if (!property || size != (2 * sizeof(u32))) {
+		dev_err(sei->dev, "Missing subnode 'reg' property\n");
+		ret = -ENODEV;
+		goto remove_ap_domain;
+	}
+
+	sei->cp_interrupts.first = be32_to_cpu(property[0]);
+	sei->cp_interrupts.number = be32_to_cpu(property[1]);
+	sei->cp_domain = irq_domain_create_hierarchy(parent_domain, 0,
+						     sei->cp_interrupts.number,
+						     of_node_to_fwnode(child),
+						     &mvebu_sei_cp_domain_ops,
+						     sei);
+	if (!sei->cp_domain) {
+		pr_err("Failed to create CPs IRQ domain\n");
+		ret = -ENOMEM;
+		goto remove_ap_domain;
+	}
+
+	plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(child),
+						     &mvebu_sei_msi_domain_info,
+						     sei->cp_domain);
+	if (!plat_domain) {
+		pr_err("Failed to create CPs MSI domain\n");
+		ret = -ENOMEM;
+		goto remove_cp_domain;
+	}
+
+	platform_set_drvdata(pdev, sei);
+
+	mvebu_sei_reset(sei);
+
+	return 0;
+
+remove_cp_domain:
+	irq_domain_remove(sei->cp_domain);
+remove_ap_domain:
+	irq_domain_remove(sei->ap_domain);
+dispose_irq:
+	irq_dispose_mapping(top_level_spi);
+
+	return ret;
+}
+
+static const struct of_device_id mvebu_sei_of_match[] = {
+	{ .compatible = "marvell,armada-8k-sei", },
+	{},
+};
+
+static struct platform_driver mvebu_sei_driver = {
+	.probe  = mvebu_sei_probe,
+	.driver = {
+		.name = "mvebu-sei",
+		.of_match_table = mvebu_sei_of_match,
+	},
+};
+builtin_platform_driver(mvebu_sei_driver);
diff --git a/drivers/irqchip/irq-mvebu-sei.h b/drivers/irqchip/irq-mvebu-sei.h
new file mode 100644
index 000000000000..f0c12a441923
--- /dev/null
+++ b/drivers/irqchip/irq-mvebu-sei.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MVEBU_SEI_H__
+#define __MVEBU_SEI_H__
+
+#include <linux/types.h>
+
+struct device_node;
+
+int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
+			    phys_addr_t *clr);
+
+#endif /* __MVEBU_SEI_H__ */
-- 
2.14.1

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

* [PATCH 11/17] arm64: marvell: enable SEI driver
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Enable the newly introduced Marvell SEI driver for the 64-bit Marvell
EBU platforms.

Suggested-by: Haim Boot <hayim@marvell.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/Kconfig.platforms | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 2b1535cdeb7c..dc3c42938051 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -121,6 +121,7 @@ config ARCH_MVEBU
 	select MVEBU_ICU
 	select MVEBU_ODMI
 	select MVEBU_PIC
+	select MVEBU_SEI
 	select OF_GPIO
 	select PINCTRL
 	select PINCTRL_ARMADA_37XX
-- 
2.14.1

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

* [PATCH 11/17] arm64: marvell: enable SEI driver
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

Enable the newly introduced Marvell SEI driver for the 64-bit Marvell
EBU platforms.

Suggested-by: Haim Boot <hayim@marvell.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/Kconfig.platforms | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 2b1535cdeb7c..dc3c42938051 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -121,6 +121,7 @@ config ARCH_MVEBU
 	select MVEBU_ICU
 	select MVEBU_ODMI
 	select MVEBU_PIC
+	select MVEBU_SEI
 	select OF_GPIO
 	select PINCTRL
 	select PINCTRL_ARMADA_37XX
-- 
2.14.1

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

* [PATCH 12/17] irqchip/irq-mvebu-icu: add support for System Error Interrupts (SEI)
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

An SEI driver provides an MSI domain through which it is possible to
raise SEIs.

Handle the NSR probe function in a more generic way to support other
type of interrupts (ie. the SEIs).

For clarity we do not use tree IRQ domains for now but linear ones
instead, allocating the 207 ICU lines for each interrupt group.
Reallocating an ICU slot is prevented by the use of an ICU-wide bitmap.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 132 +++++++++++++++++++++++++++++++++-------
 1 file changed, 110 insertions(+), 22 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 1d3cd112619c..862541f2d135 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -24,12 +24,17 @@
 #include <dt-bindings/interrupt-controller/mvebu-icu.h>
 
 #include "irq-mvebu-gicp.h"
+#include "irq-mvebu-sei.h"
 
 /* ICU registers */
 #define ICU_SETSPI_NSR_AL	0x10
 #define ICU_SETSPI_NSR_AH	0x14
 #define ICU_CLRSPI_NSR_AL	0x18
 #define ICU_CLRSPI_NSR_AH	0x1c
+#define ICU_SET_SEI_AL		0x50
+#define ICU_SET_SEI_AH		0x54
+#define ICU_CLR_SEI_AL		0x58
+#define ICU_CLR_SEI_AH		0x5C
 #define ICU_INT_CFG(x)          (0x100 + 4 * (x))
 #define   ICU_INT_ENABLE	BIT(24)
 #define   ICU_IS_EDGE		BIT(28)
@@ -40,11 +45,29 @@
 #define ICU_SATA0_ICU_ID	109
 #define ICU_SATA1_ICU_ID	107
 
+struct mvebu_icu_subset_data {
+	int (*get_doorbells)(struct device_node *msi_parent_dn,
+			     phys_addr_t *set, phys_addr_t *clr);
+	unsigned int offset_set_ah;
+	unsigned int offset_set_al;
+	unsigned int offset_clr_ah;
+	unsigned int offset_clr_al;
+	unsigned int icu_group;
+};
+
 struct mvebu_icu {
 	struct irq_chip irq_chip;
 	struct regmap *regmap;
 	struct device *dev;
 	bool legacy_bindings;
+	/* Lock on interrupt allocations/releases */
+	spinlock_t msi_lock;
+	DECLARE_BITMAP(msi_bitmap, ICU_MAX_IRQS);
+};
+
+struct mvebu_icu_msi_data {
+	struct mvebu_icu *icu;
+	const struct mvebu_icu_subset_data *subset_data;
 };
 
 struct mvebu_icu_irq_data {
@@ -115,7 +138,8 @@ static int
 mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
 			       unsigned long *hwirq, unsigned int *type)
 {
-	struct mvebu_icu *icu = platform_msi_get_host_data(d);
+	struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d);
+	struct mvebu_icu *icu = msi_data->icu;
 	unsigned int param_count = icu->legacy_bindings ? 3 : 2;
 
 	/* Check the count of the parameters in dt */
@@ -156,7 +180,9 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 	int err;
 	unsigned long hwirq;
 	struct irq_fwspec *fwspec = args;
-	struct mvebu_icu *icu = platform_msi_get_host_data(domain);
+	struct mvebu_icu_msi_data *msi_data =
+		platform_msi_get_host_data(domain);
+	struct mvebu_icu *icu = msi_data->icu;
 	struct mvebu_icu_irq_data *icu_irqd;
 
 	icu_irqd = kmalloc(sizeof(*icu_irqd), GFP_KERNEL);
@@ -170,16 +196,22 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 		goto free_irqd;
 	}
 
+	spin_lock(&icu->msi_lock);
+	err = bitmap_allocate_region(icu->msi_bitmap, hwirq, 0);
+	spin_unlock(&icu->msi_lock);
+	if (err < 0)
+		goto free_irqd;
+
 	if (icu->legacy_bindings)
 		icu_irqd->icu_group = fwspec->param[0];
 	else
-		icu_irqd->icu_group = ICU_GRP_NSR;
+		icu_irqd->icu_group = msi_data->subset_data->icu_group;
 	icu_irqd->icu = icu;
 
 	err = platform_msi_domain_alloc(domain, virq, nr_irqs);
 	if (err) {
 		dev_err(icu->dev, "failed to allocate ICU interrupt in parent domain\n");
-		goto free_irqd;
+		goto free_bitmap;
 	}
 
 	/* Make sure there is no interrupt left pending by the firmware */
@@ -198,6 +230,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 
 free_msi:
 	platform_msi_domain_free(domain, virq, nr_irqs);
+free_bitmap:
+	spin_lock(&icu->msi_lock);
+	bitmap_release_region(icu->msi_bitmap, hwirq, 0);
+	spin_unlock(&icu->msi_lock);
 free_irqd:
 	kfree(icu_irqd);
 	return err;
@@ -207,12 +243,19 @@ static void
 mvebu_icu_irq_domain_free(struct irq_domain *domain, unsigned int virq,
 			  unsigned int nr_irqs)
 {
+	struct mvebu_icu_msi_data *msi_data =
+		platform_msi_get_host_data(domain);
+	struct mvebu_icu *icu = msi_data->icu;
 	struct irq_data *d = irq_get_irq_data(virq);
 	struct mvebu_icu_irq_data *icu_irqd = d->chip_data;
 
 	kfree(icu_irqd);
 
 	platform_msi_domain_free(domain, virq, nr_irqs);
+
+	spin_lock(&icu->msi_lock);
+	bitmap_release_region(icu->msi_bitmap, d->hwirq, 0);
+	spin_unlock(&icu->msi_lock);
 }
 
 static const struct irq_domain_ops mvebu_icu_domain_ops = {
@@ -221,18 +264,33 @@ static const struct irq_domain_ops mvebu_icu_domain_ops = {
 	.free      = mvebu_icu_irq_domain_free,
 };
 
-static int mvebu_icu_nsr_probe(struct platform_device *pdev)
+static int mvebu_icu_subset_probe(struct platform_device *pdev)
 {
+	const struct mvebu_icu_subset_data *subset;
+	struct mvebu_icu_msi_data *msi_data;
 	struct device_node *msi_parent_dn;
 	struct irq_domain *irq_domain;
 	struct mvebu_icu *icu;
 	phys_addr_t set, clr;
 	int ret;
 
+	msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL);
+	if (!msi_data)
+		return -ENOMEM;
+
 	icu = mvebu_dev_get_drvdata(pdev);
 	if (IS_ERR(icu))
 		return PTR_ERR(icu);
 
+	subset = of_device_get_match_data(&pdev->dev);
+	if (!subset) {
+		dev_err(&pdev->dev, "Could not retrieve subset data\n");
+		return -EINVAL;
+	}
+
+	msi_data->icu = icu;
+	msi_data->subset_data = subset;
+
 	pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, pdev->dev.of_node,
 						 DOMAIN_BUS_PLATFORM_MSI);
 	if (!pdev->dev.msi_domain)
@@ -243,19 +301,19 @@ static int mvebu_icu_nsr_probe(struct platform_device *pdev)
 		return -ENODEV;
 
 	/* Set Clear/Set ICU NSR SPI message address in AP */
-	ret = mvebu_gicp_get_doorbells(msi_parent_dn, &set, &clr);
+	ret = subset->get_doorbells(msi_parent_dn, &set, &clr);
 	if (ret)
 		return ret;
 
-	regmap_write(icu->regmap, ICU_SETSPI_NSR_AH, upper_32_bits(set));
-	regmap_write(icu->regmap, ICU_SETSPI_NSR_AL, lower_32_bits(set));
-	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AH, upper_32_bits(clr));
-	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AL, lower_32_bits(clr));
+	regmap_write(icu->regmap, subset->offset_set_ah, upper_32_bits(set));
+	regmap_write(icu->regmap, subset->offset_set_al, lower_32_bits(set));
+	regmap_write(icu->regmap, subset->offset_clr_ah, upper_32_bits(clr));
+	regmap_write(icu->regmap, subset->offset_clr_al, lower_32_bits(clr));
 
 	irq_domain = platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS,
 						       mvebu_icu_write_msg,
 						       &mvebu_icu_domain_ops,
-						       icu);
+						       msi_data);
 	if (!irq_domain) {
 		dev_err(&pdev->dev, "Failed to create ICU MSI domain\n");
 		return -ENOMEM;
@@ -264,19 +322,44 @@ static int mvebu_icu_nsr_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id mvebu_icu_nsr_of_match[] = {
-	{ .compatible = "marvell,cp110-icu-nsr", },
+static const struct mvebu_icu_subset_data mvebu_icu_nsr_subset_data = {
+	.get_doorbells = mvebu_gicp_get_doorbells,
+	.offset_set_ah = ICU_SETSPI_NSR_AH,
+	.offset_set_al = ICU_SETSPI_NSR_AL,
+	.offset_clr_ah = ICU_CLRSPI_NSR_AH,
+	.offset_clr_al = ICU_CLRSPI_NSR_AL,
+	.icu_group = ICU_GRP_NSR,
+};
+
+static const struct mvebu_icu_subset_data mvebu_icu_sei_subset_data = {
+	.get_doorbells = mvebu_sei_get_doorbells,
+	.offset_set_ah = ICU_SET_SEI_AH,
+	.offset_set_al = ICU_SET_SEI_AL,
+	.offset_clr_ah = ICU_CLR_SEI_AH,
+	.offset_clr_al = ICU_CLR_SEI_AL,
+	.icu_group = ICU_GRP_SEI,
+};
+
+static const struct of_device_id mvebu_icu_subset_of_match[] = {
+	{
+		.compatible = "marvell,cp110-icu-nsr",
+		.data = &mvebu_icu_nsr_subset_data,
+	},
+	{
+		.compatible = "marvell,cp110-icu-sei",
+		.data = &mvebu_icu_sei_subset_data,
+	},
 	{},
 };
 
-static struct platform_driver mvebu_icu_nsr_driver = {
-	.probe  = mvebu_icu_nsr_probe,
+static struct platform_driver mvebu_icu_subset_drivers = {
+	.probe  = mvebu_icu_subset_probe,
 	.driver = {
-		.name = "mvebu-icu-nsr",
-		.of_match_table = mvebu_icu_nsr_of_match,
+		.name = "mvebu-icu-subset",
+		.of_match_table = mvebu_icu_subset_of_match,
 	},
 };
-builtin_platform_driver(mvebu_icu_nsr_driver);
+builtin_platform_driver(mvebu_icu_subset_drivers);
 
 static int mvebu_icu_probe(struct platform_device *pdev)
 {
@@ -291,6 +374,8 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 
 	icu->dev = &pdev->dev;
 
+	spin_lock_init(&icu->msi_lock);
+
 	icu->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, NULL);
 	if (IS_ERR(icu->regmap))
 		return PTR_ERR(icu->regmap);
@@ -323,7 +408,7 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 #endif
 
 	/*
-	 * Clean all ICU interrupts with type SPI_NSR, required to
+	 * Clean all ICU interrupts of type SPI_NSR and SEI, required to
 	 * avoid unpredictable SPI assignments done by firmware.
 	 */
 	for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
@@ -332,20 +417,23 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 		regmap_read(icu->regmap, ICU_INT_CFG(i), &icu_int);
 		icu_grp = icu_int >> ICU_GROUP_SHIFT;
 
-		if (icu_grp == ICU_GRP_NSR)
+		if (icu_grp == ICU_GRP_NSR ||
+		    (icu_grp == ICU_GRP_SEI && !icu->legacy_bindings))
 			regmap_write(icu->regmap, ICU_INT_CFG(i), 0);
 	}
 
 	platform_set_drvdata(pdev, icu);
 
 	if (icu->legacy_bindings)
-		return mvebu_icu_nsr_probe(pdev);
+		return mvebu_icu_subset_probe(pdev);
 	else
 		return devm_of_platform_populate(&pdev->dev);
 }
 
 static const struct of_device_id mvebu_icu_of_match[] = {
-	{ .compatible = "marvell,cp110-icu", },
+	{
+		.compatible = "marvell,cp110-icu",
+	},
 	{},
 };
 
-- 
2.14.1

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

* [PATCH 12/17] irqchip/irq-mvebu-icu: add support for System Error Interrupts (SEI)
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

An SEI driver provides an MSI domain through which it is possible to
raise SEIs.

Handle the NSR probe function in a more generic way to support other
type of interrupts (ie. the SEIs).

For clarity we do not use tree IRQ domains for now but linear ones
instead, allocating the 207 ICU lines for each interrupt group.
Reallocating an ICU slot is prevented by the use of an ICU-wide bitmap.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/irqchip/irq-mvebu-icu.c | 132 +++++++++++++++++++++++++++++++++-------
 1 file changed, 110 insertions(+), 22 deletions(-)

diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 1d3cd112619c..862541f2d135 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -24,12 +24,17 @@
 #include <dt-bindings/interrupt-controller/mvebu-icu.h>
 
 #include "irq-mvebu-gicp.h"
+#include "irq-mvebu-sei.h"
 
 /* ICU registers */
 #define ICU_SETSPI_NSR_AL	0x10
 #define ICU_SETSPI_NSR_AH	0x14
 #define ICU_CLRSPI_NSR_AL	0x18
 #define ICU_CLRSPI_NSR_AH	0x1c
+#define ICU_SET_SEI_AL		0x50
+#define ICU_SET_SEI_AH		0x54
+#define ICU_CLR_SEI_AL		0x58
+#define ICU_CLR_SEI_AH		0x5C
 #define ICU_INT_CFG(x)          (0x100 + 4 * (x))
 #define   ICU_INT_ENABLE	BIT(24)
 #define   ICU_IS_EDGE		BIT(28)
@@ -40,11 +45,29 @@
 #define ICU_SATA0_ICU_ID	109
 #define ICU_SATA1_ICU_ID	107
 
+struct mvebu_icu_subset_data {
+	int (*get_doorbells)(struct device_node *msi_parent_dn,
+			     phys_addr_t *set, phys_addr_t *clr);
+	unsigned int offset_set_ah;
+	unsigned int offset_set_al;
+	unsigned int offset_clr_ah;
+	unsigned int offset_clr_al;
+	unsigned int icu_group;
+};
+
 struct mvebu_icu {
 	struct irq_chip irq_chip;
 	struct regmap *regmap;
 	struct device *dev;
 	bool legacy_bindings;
+	/* Lock on interrupt allocations/releases */
+	spinlock_t msi_lock;
+	DECLARE_BITMAP(msi_bitmap, ICU_MAX_IRQS);
+};
+
+struct mvebu_icu_msi_data {
+	struct mvebu_icu *icu;
+	const struct mvebu_icu_subset_data *subset_data;
 };
 
 struct mvebu_icu_irq_data {
@@ -115,7 +138,8 @@ static int
 mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
 			       unsigned long *hwirq, unsigned int *type)
 {
-	struct mvebu_icu *icu = platform_msi_get_host_data(d);
+	struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d);
+	struct mvebu_icu *icu = msi_data->icu;
 	unsigned int param_count = icu->legacy_bindings ? 3 : 2;
 
 	/* Check the count of the parameters in dt */
@@ -156,7 +180,9 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 	int err;
 	unsigned long hwirq;
 	struct irq_fwspec *fwspec = args;
-	struct mvebu_icu *icu = platform_msi_get_host_data(domain);
+	struct mvebu_icu_msi_data *msi_data =
+		platform_msi_get_host_data(domain);
+	struct mvebu_icu *icu = msi_data->icu;
 	struct mvebu_icu_irq_data *icu_irqd;
 
 	icu_irqd = kmalloc(sizeof(*icu_irqd), GFP_KERNEL);
@@ -170,16 +196,22 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 		goto free_irqd;
 	}
 
+	spin_lock(&icu->msi_lock);
+	err = bitmap_allocate_region(icu->msi_bitmap, hwirq, 0);
+	spin_unlock(&icu->msi_lock);
+	if (err < 0)
+		goto free_irqd;
+
 	if (icu->legacy_bindings)
 		icu_irqd->icu_group = fwspec->param[0];
 	else
-		icu_irqd->icu_group = ICU_GRP_NSR;
+		icu_irqd->icu_group = msi_data->subset_data->icu_group;
 	icu_irqd->icu = icu;
 
 	err = platform_msi_domain_alloc(domain, virq, nr_irqs);
 	if (err) {
 		dev_err(icu->dev, "failed to allocate ICU interrupt in parent domain\n");
-		goto free_irqd;
+		goto free_bitmap;
 	}
 
 	/* Make sure there is no interrupt left pending by the firmware */
@@ -198,6 +230,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 
 free_msi:
 	platform_msi_domain_free(domain, virq, nr_irqs);
+free_bitmap:
+	spin_lock(&icu->msi_lock);
+	bitmap_release_region(icu->msi_bitmap, hwirq, 0);
+	spin_unlock(&icu->msi_lock);
 free_irqd:
 	kfree(icu_irqd);
 	return err;
@@ -207,12 +243,19 @@ static void
 mvebu_icu_irq_domain_free(struct irq_domain *domain, unsigned int virq,
 			  unsigned int nr_irqs)
 {
+	struct mvebu_icu_msi_data *msi_data =
+		platform_msi_get_host_data(domain);
+	struct mvebu_icu *icu = msi_data->icu;
 	struct irq_data *d = irq_get_irq_data(virq);
 	struct mvebu_icu_irq_data *icu_irqd = d->chip_data;
 
 	kfree(icu_irqd);
 
 	platform_msi_domain_free(domain, virq, nr_irqs);
+
+	spin_lock(&icu->msi_lock);
+	bitmap_release_region(icu->msi_bitmap, d->hwirq, 0);
+	spin_unlock(&icu->msi_lock);
 }
 
 static const struct irq_domain_ops mvebu_icu_domain_ops = {
@@ -221,18 +264,33 @@ static const struct irq_domain_ops mvebu_icu_domain_ops = {
 	.free      = mvebu_icu_irq_domain_free,
 };
 
-static int mvebu_icu_nsr_probe(struct platform_device *pdev)
+static int mvebu_icu_subset_probe(struct platform_device *pdev)
 {
+	const struct mvebu_icu_subset_data *subset;
+	struct mvebu_icu_msi_data *msi_data;
 	struct device_node *msi_parent_dn;
 	struct irq_domain *irq_domain;
 	struct mvebu_icu *icu;
 	phys_addr_t set, clr;
 	int ret;
 
+	msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL);
+	if (!msi_data)
+		return -ENOMEM;
+
 	icu = mvebu_dev_get_drvdata(pdev);
 	if (IS_ERR(icu))
 		return PTR_ERR(icu);
 
+	subset = of_device_get_match_data(&pdev->dev);
+	if (!subset) {
+		dev_err(&pdev->dev, "Could not retrieve subset data\n");
+		return -EINVAL;
+	}
+
+	msi_data->icu = icu;
+	msi_data->subset_data = subset;
+
 	pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, pdev->dev.of_node,
 						 DOMAIN_BUS_PLATFORM_MSI);
 	if (!pdev->dev.msi_domain)
@@ -243,19 +301,19 @@ static int mvebu_icu_nsr_probe(struct platform_device *pdev)
 		return -ENODEV;
 
 	/* Set Clear/Set ICU NSR SPI message address in AP */
-	ret = mvebu_gicp_get_doorbells(msi_parent_dn, &set, &clr);
+	ret = subset->get_doorbells(msi_parent_dn, &set, &clr);
 	if (ret)
 		return ret;
 
-	regmap_write(icu->regmap, ICU_SETSPI_NSR_AH, upper_32_bits(set));
-	regmap_write(icu->regmap, ICU_SETSPI_NSR_AL, lower_32_bits(set));
-	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AH, upper_32_bits(clr));
-	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AL, lower_32_bits(clr));
+	regmap_write(icu->regmap, subset->offset_set_ah, upper_32_bits(set));
+	regmap_write(icu->regmap, subset->offset_set_al, lower_32_bits(set));
+	regmap_write(icu->regmap, subset->offset_clr_ah, upper_32_bits(clr));
+	regmap_write(icu->regmap, subset->offset_clr_al, lower_32_bits(clr));
 
 	irq_domain = platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS,
 						       mvebu_icu_write_msg,
 						       &mvebu_icu_domain_ops,
-						       icu);
+						       msi_data);
 	if (!irq_domain) {
 		dev_err(&pdev->dev, "Failed to create ICU MSI domain\n");
 		return -ENOMEM;
@@ -264,19 +322,44 @@ static int mvebu_icu_nsr_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id mvebu_icu_nsr_of_match[] = {
-	{ .compatible = "marvell,cp110-icu-nsr", },
+static const struct mvebu_icu_subset_data mvebu_icu_nsr_subset_data = {
+	.get_doorbells = mvebu_gicp_get_doorbells,
+	.offset_set_ah = ICU_SETSPI_NSR_AH,
+	.offset_set_al = ICU_SETSPI_NSR_AL,
+	.offset_clr_ah = ICU_CLRSPI_NSR_AH,
+	.offset_clr_al = ICU_CLRSPI_NSR_AL,
+	.icu_group = ICU_GRP_NSR,
+};
+
+static const struct mvebu_icu_subset_data mvebu_icu_sei_subset_data = {
+	.get_doorbells = mvebu_sei_get_doorbells,
+	.offset_set_ah = ICU_SET_SEI_AH,
+	.offset_set_al = ICU_SET_SEI_AL,
+	.offset_clr_ah = ICU_CLR_SEI_AH,
+	.offset_clr_al = ICU_CLR_SEI_AL,
+	.icu_group = ICU_GRP_SEI,
+};
+
+static const struct of_device_id mvebu_icu_subset_of_match[] = {
+	{
+		.compatible = "marvell,cp110-icu-nsr",
+		.data = &mvebu_icu_nsr_subset_data,
+	},
+	{
+		.compatible = "marvell,cp110-icu-sei",
+		.data = &mvebu_icu_sei_subset_data,
+	},
 	{},
 };
 
-static struct platform_driver mvebu_icu_nsr_driver = {
-	.probe  = mvebu_icu_nsr_probe,
+static struct platform_driver mvebu_icu_subset_drivers = {
+	.probe  = mvebu_icu_subset_probe,
 	.driver = {
-		.name = "mvebu-icu-nsr",
-		.of_match_table = mvebu_icu_nsr_of_match,
+		.name = "mvebu-icu-subset",
+		.of_match_table = mvebu_icu_subset_of_match,
 	},
 };
-builtin_platform_driver(mvebu_icu_nsr_driver);
+builtin_platform_driver(mvebu_icu_subset_drivers);
 
 static int mvebu_icu_probe(struct platform_device *pdev)
 {
@@ -291,6 +374,8 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 
 	icu->dev = &pdev->dev;
 
+	spin_lock_init(&icu->msi_lock);
+
 	icu->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, NULL);
 	if (IS_ERR(icu->regmap))
 		return PTR_ERR(icu->regmap);
@@ -323,7 +408,7 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 #endif
 
 	/*
-	 * Clean all ICU interrupts with type SPI_NSR, required to
+	 * Clean all ICU interrupts of type SPI_NSR and SEI, required to
 	 * avoid unpredictable SPI assignments done by firmware.
 	 */
 	for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
@@ -332,20 +417,23 @@ static int mvebu_icu_probe(struct platform_device *pdev)
 		regmap_read(icu->regmap, ICU_INT_CFG(i), &icu_int);
 		icu_grp = icu_int >> ICU_GROUP_SHIFT;
 
-		if (icu_grp == ICU_GRP_NSR)
+		if (icu_grp == ICU_GRP_NSR ||
+		    (icu_grp == ICU_GRP_SEI && !icu->legacy_bindings))
 			regmap_write(icu->regmap, ICU_INT_CFG(i), 0);
 	}
 
 	platform_set_drvdata(pdev, icu);
 
 	if (icu->legacy_bindings)
-		return mvebu_icu_nsr_probe(pdev);
+		return mvebu_icu_subset_probe(pdev);
 	else
 		return devm_of_platform_populate(&pdev->dev);
 }
 
 static const struct of_device_id mvebu_icu_of_match[] = {
-	{ .compatible = "marvell,cp110-icu", },
+	{
+		.compatible = "marvell,cp110-icu",
+	},
 	{},
 };
 
-- 
2.14.1

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

* [PATCH 13/17] dt-bindings/interrupt-controller: update Marvell ICU bindings
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Change the documentation to reflect the new bindings used for Marvell
ICU. This involves describing each interrupt group as a subnode of the
ICU node. Each of them having their own compatible.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 .../bindings/interrupt-controller/marvell,icu.txt  | 60 ++++++++++++++++------
 1 file changed, 43 insertions(+), 17 deletions(-)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
index 649b7ec9d9b1..b856e91105e4 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
@@ -5,6 +5,8 @@ The Marvell ICU (Interrupt Consolidation Unit) controller is
 responsible for collecting all wired-interrupt sources in the CP and
 communicating them to the GIC in the AP, the unit translates interrupt
 requests on input wires to MSG memory mapped transactions to the GIC.
+These messages will access a different GIC memory area depending on
+their type (NSR, SR, SEI, REI, etc).
 
 Required properties:
 
@@ -12,20 +14,19 @@ Required properties:
 
 - reg: Should contain ICU registers location and length.
 
+Subnodes: Each group of interrupt is declared as a subnode of the ICU,
+with their own compatible.
+
+Required properties for the icu_nsr/icu_sei subnodes:
+
+- compatible: Should be "marvell,cp110-icu-nsr" or "marvell,cp110-icu-sei".
+
 - #interrupt-cells: Specifies the number of cells needed to encode an
-  interrupt source. The value shall be 3.
+  interrupt source. The value shall be 2.
 
-  The 1st cell is the group type of the ICU interrupt. Possible group
-  types are:
+  The 1st cell is the index of the interrupt in the ICU unit.
 
-   ICU_GRP_NSR (0x0) : Shared peripheral interrupt, non-secure
-   ICU_GRP_SR  (0x1) : Shared peripheral interrupt, secure
-   ICU_GRP_SEI (0x4) : System error interrupt
-   ICU_GRP_REI (0x5) : RAM error interrupt
-
-  The 2nd cell is the index of the interrupt in the ICU unit.
-
-  The 3rd cell is the type of the interrupt. See arm,gic.txt for
+  The 2nd cell is the type of the interrupt. See arm,gic.txt for
   details.
 
 - interrupt-controller: Identifies the node as an interrupt
@@ -35,17 +36,42 @@ Required properties:
   that allows to trigger interrupts using MSG memory mapped
   transactions.
 
+Note: each 'interrupts' property referring to any 'icu_xxx' node shall
+      have a different number within [0:206].
+
 Example:
 
 icu: interrupt-controller@1e0000 {
 	compatible = "marvell,cp110-icu";
 	reg = <0x1e0000 0x440>;
-	#interrupt-cells = <3>;
-	interrupt-controller;
-	msi-parent = <&gicp>;
+
+	CP110_LABEL(icu_nsr): icu-nsr {
+		compatible = "marvell,cp110-icu-nsr";
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		msi-parent = <&gicp>;
+	};
+
+        CP110_LABEL(icu_sei): icu-sei {
+                compatible = "marvell,cp110-icu-sei";
+                #interrupt-cells = <2>;
+                interrupt-controller;
+                msi-parent = <&sei>;
+        };
+};
+
+node1 {
+	interrupt-parent = <&icu_nsr>;
+	interrupts = <106 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+node2 {
+	interrupt-parent = <&icu_sei>;
+	interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
 };
 
-usb3h0: usb3@500000 {
-	interrupt-parent = <&icu>;
-	interrupts = <ICU_GRP_NSR 106 IRQ_TYPE_LEVEL_HIGH>;
+/* Would not work with the above nodes */
+node3 {
+	interrupt-parent = <&icu_nsr>;
+	interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
 };
-- 
2.14.1

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

* [PATCH 13/17] dt-bindings/interrupt-controller: update Marvell ICU bindings
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

Change the documentation to reflect the new bindings used for Marvell
ICU. This involves describing each interrupt group as a subnode of the
ICU node. Each of them having their own compatible.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 .../bindings/interrupt-controller/marvell,icu.txt  | 60 ++++++++++++++++------
 1 file changed, 43 insertions(+), 17 deletions(-)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
index 649b7ec9d9b1..b856e91105e4 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt
@@ -5,6 +5,8 @@ The Marvell ICU (Interrupt Consolidation Unit) controller is
 responsible for collecting all wired-interrupt sources in the CP and
 communicating them to the GIC in the AP, the unit translates interrupt
 requests on input wires to MSG memory mapped transactions to the GIC.
+These messages will access a different GIC memory area depending on
+their type (NSR, SR, SEI, REI, etc).
 
 Required properties:
 
@@ -12,20 +14,19 @@ Required properties:
 
 - reg: Should contain ICU registers location and length.
 
+Subnodes: Each group of interrupt is declared as a subnode of the ICU,
+with their own compatible.
+
+Required properties for the icu_nsr/icu_sei subnodes:
+
+- compatible: Should be "marvell,cp110-icu-nsr" or "marvell,cp110-icu-sei".
+
 - #interrupt-cells: Specifies the number of cells needed to encode an
-  interrupt source. The value shall be 3.
+  interrupt source. The value shall be 2.
 
-  The 1st cell is the group type of the ICU interrupt. Possible group
-  types are:
+  The 1st cell is the index of the interrupt in the ICU unit.
 
-   ICU_GRP_NSR (0x0) : Shared peripheral interrupt, non-secure
-   ICU_GRP_SR  (0x1) : Shared peripheral interrupt, secure
-   ICU_GRP_SEI (0x4) : System error interrupt
-   ICU_GRP_REI (0x5) : RAM error interrupt
-
-  The 2nd cell is the index of the interrupt in the ICU unit.
-
-  The 3rd cell is the type of the interrupt. See arm,gic.txt for
+  The 2nd cell is the type of the interrupt. See arm,gic.txt for
   details.
 
 - interrupt-controller: Identifies the node as an interrupt
@@ -35,17 +36,42 @@ Required properties:
   that allows to trigger interrupts using MSG memory mapped
   transactions.
 
+Note: each 'interrupts' property referring to any 'icu_xxx' node shall
+      have a different number within [0:206].
+
 Example:
 
 icu: interrupt-controller at 1e0000 {
 	compatible = "marvell,cp110-icu";
 	reg = <0x1e0000 0x440>;
-	#interrupt-cells = <3>;
-	interrupt-controller;
-	msi-parent = <&gicp>;
+
+	CP110_LABEL(icu_nsr): icu-nsr {
+		compatible = "marvell,cp110-icu-nsr";
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		msi-parent = <&gicp>;
+	};
+
+        CP110_LABEL(icu_sei): icu-sei {
+                compatible = "marvell,cp110-icu-sei";
+                #interrupt-cells = <2>;
+                interrupt-controller;
+                msi-parent = <&sei>;
+        };
+};
+
+node1 {
+	interrupt-parent = <&icu_nsr>;
+	interrupts = <106 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+node2 {
+	interrupt-parent = <&icu_sei>;
+	interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
 };
 
-usb3h0: usb3 at 500000 {
-	interrupt-parent = <&icu>;
-	interrupts = <ICU_GRP_NSR 106 IRQ_TYPE_LEVEL_HIGH>;
+/* Would not work with the above nodes */
+node3 {
+	interrupt-parent = <&icu_nsr>;
+	interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
 };
-- 
2.14.1

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

* [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Describe the SEI (System Error Interrupt) controller driver. The
controller is part of the GIC. It aggregates two types of interrupts,
wired and MSIs from respectively the AP and the CPs, into a single SPI
interrupt.

Suggested-by: Haim Boot <hayim@marvell.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 .../bindings/interrupt-controller/marvell,sei.txt  | 54 ++++++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt

diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
new file mode 100644
index 000000000000..a246d59552b1
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
@@ -0,0 +1,54 @@
+Marvell SEI (System Error Interrupt) Controller
+-----------------------------------------------
+
+Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
+It receives interrupts from several sources and aggregates them to a single
+interrupt line (an SPI) on the primary interrupt controller.
+
+The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is
+wired while a second set comes from the CPs by the mean of MSIs. Each
+'domain' is represented as a subnode.
+
+Required properties:
+
+- compatible: should be "marvell,armada-8k-sei".
+- reg: SEI registers location and length.
+- interrupts: identifies the parent IRQ that will be triggered.
+- #address-cells: should be '1', represents the position of the first
+                  IRQ of a given type in the SEI range.
+- #size-cells: should be '1', represents the number of a given type of
+               IRQs.
+
+Child node 'sei-wired-controller' required properties:
+
+- reg: the range of wired interrupts.
+- #interrupt-cells: number of cells to define an SEI wired interrupt
+                    coming from the AP, should be 1. The cell is the IRQ
+                    number.
+- interrupt-controller: identifies the node as an interrupt controller.
+
+Child node 'sei-msi-controller' required properties:
+
+- reg: the range of non-wired interrupts triggered by way of MSIs.
+- msi-controller: identifies the node as an MSI controller.
+
+Example:
+
+        sei: sei@3f0200 {
+               compatible = "marvell,armada-8k-sei";
+               reg = <0x3f0200 0x40>;
+               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               sei_wired_controller: sei-wired-controller@0 {
+                       reg = <0 21>;
+                       #interrupt-cells = <1>;
+                       interrupt-controller;
+               };
+
+               sei_msi_controller: sei-msi-controller@21 {
+                       reg = <21 43>;
+                       msi-controller;
+               };
+       };
-- 
2.14.1

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

* [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

Describe the SEI (System Error Interrupt) controller driver. The
controller is part of the GIC. It aggregates two types of interrupts,
wired and MSIs from respectively the AP and the CPs, into a single SPI
interrupt.

Suggested-by: Haim Boot <hayim@marvell.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 .../bindings/interrupt-controller/marvell,sei.txt  | 54 ++++++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt

diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
new file mode 100644
index 000000000000..a246d59552b1
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
@@ -0,0 +1,54 @@
+Marvell SEI (System Error Interrupt) Controller
+-----------------------------------------------
+
+Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
+It receives interrupts from several sources and aggregates them to a single
+interrupt line (an SPI) on the primary interrupt controller.
+
+The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is
+wired while a second set comes from the CPs by the mean of MSIs. Each
+'domain' is represented as a subnode.
+
+Required properties:
+
+- compatible: should be "marvell,armada-8k-sei".
+- reg: SEI registers location and length.
+- interrupts: identifies the parent IRQ that will be triggered.
+- #address-cells: should be '1', represents the position of the first
+                  IRQ of a given type in the SEI range.
+- #size-cells: should be '1', represents the number of a given type of
+               IRQs.
+
+Child node 'sei-wired-controller' required properties:
+
+- reg: the range of wired interrupts.
+- #interrupt-cells: number of cells to define an SEI wired interrupt
+                    coming from the AP, should be 1. The cell is the IRQ
+                    number.
+- interrupt-controller: identifies the node as an interrupt controller.
+
+Child node 'sei-msi-controller' required properties:
+
+- reg: the range of non-wired interrupts triggered by way of MSIs.
+- msi-controller: identifies the node as an MSI controller.
+
+Example:
+
+        sei: sei at 3f0200 {
+               compatible = "marvell,armada-8k-sei";
+               reg = <0x3f0200 0x40>;
+               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               sei_wired_controller: sei-wired-controller at 0 {
+                       reg = <0 21>;
+                       #interrupt-cells = <1>;
+                       interrupt-controller;
+               };
+
+               sei_msi_controller: sei-msi-controller at 21 {
+                       reg = <21 43>;
+                       msi-controller;
+               };
+       };
-- 
2.14.1

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

* [PATCH 15/17] arm64: dts: marvell: add AP806 SEI subnode
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Add the System Error Interrupt node, representing an IRQ chip which is
part of the GIC. The SEI node has two subnodes, one for each interrupt
domain: wired (from the AP) and not-wired (MSIs from the CPs).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/boot/dts/marvell/armada-ap806.dtsi | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
index 176e38d54872..ebda3edeceed 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
@@ -124,6 +124,25 @@
 				interrupts = <GIC_PPI 15 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
+			sei: sei@3f0200 {
+				compatible = "marvell,armada-8k-sei";
+				reg = <0x3f0200 0x40>;
+				interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				sei_wired_controller: sei-wired-controller@0 {
+					reg = <0 21>;
+					#interrupt-cells = <1>;
+					interrupt-controller;
+				};
+
+				sei_msi_controller: sei-msi-controller@21 {
+					reg = <21 43>;
+					msi-controller;
+				};
+			};
+
 			xor@400000 {
 				compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
 				reg = <0x400000 0x1000>,
-- 
2.14.1

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

* [PATCH 15/17] arm64: dts: marvell: add AP806 SEI subnode
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

Add the System Error Interrupt node, representing an IRQ chip which is
part of the GIC. The SEI node has two subnodes, one for each interrupt
domain: wired (from the AP) and not-wired (MSIs from the CPs).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/boot/dts/marvell/armada-ap806.dtsi | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
index 176e38d54872..ebda3edeceed 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
@@ -124,6 +124,25 @@
 				interrupts = <GIC_PPI 15 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
+			sei: sei at 3f0200 {
+				compatible = "marvell,armada-8k-sei";
+				reg = <0x3f0200 0x40>;
+				interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				sei_wired_controller: sei-wired-controller at 0 {
+					reg = <0 21>;
+					#interrupt-cells = <1>;
+					interrupt-controller;
+				};
+
+				sei_msi_controller: sei-msi-controller at 21 {
+					reg = <21 43>;
+					msi-controller;
+				};
+			};
+
 			xor at 400000 {
 				compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
 				reg = <0x400000 0x1000>,
-- 
2.14.1

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

* [PATCH 16/17] arm64: dts: marvell: use new bindings for CP110 interrupts
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Create an ICU subnode for the NSR interrupts. This subnode becomes the
CP110 interrupt parent, removing the need for the ICU_GRP_NSR parameter.
Move all DT110 nodes to use these new bindings.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/boot/dts/marvell/armada-cp110.dtsi | 114 +++++++++++++-------------
 1 file changed, 59 insertions(+), 55 deletions(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
index 9323acdb712f..9a7bc365f5a0 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
@@ -25,7 +25,7 @@
 	#address-cells = <2>;
 	#size-cells = <2>;
 	compatible = "simple-bus";
-	interrupt-parent = <&CP110_LABEL(icu)>;
+	interrupt-parent = <&CP110_LABEL(icu_nsr)>;
 	ranges;
 
 	config-space@CP110_BASE {
@@ -46,12 +46,12 @@
 			dma-coherent;
 
 			CP110_LABEL(eth0): eth0 {
-				interrupts = <ICU_GRP_NSR 39 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 43 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 47 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 51 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 55 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 129 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <39 IRQ_TYPE_LEVEL_HIGH>,
+					     <43 IRQ_TYPE_LEVEL_HIGH>,
+					     <47 IRQ_TYPE_LEVEL_HIGH>,
+					     <51 IRQ_TYPE_LEVEL_HIGH>,
+					     <55 IRQ_TYPE_LEVEL_HIGH>,
+					     <129 IRQ_TYPE_LEVEL_HIGH>;
 				interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2",
 					"tx-cpu3", "rx-shared", "link";
 				port-id = <0>;
@@ -60,12 +60,12 @@
 			};
 
 			CP110_LABEL(eth1): eth1 {
-				interrupts = <ICU_GRP_NSR 40 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 44 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 48 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 52 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 56 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 128 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <40 IRQ_TYPE_LEVEL_HIGH>,
+					     <44 IRQ_TYPE_LEVEL_HIGH>,
+					     <48 IRQ_TYPE_LEVEL_HIGH>,
+					     <52 IRQ_TYPE_LEVEL_HIGH>,
+					     <56 IRQ_TYPE_LEVEL_HIGH>,
+					     <128 IRQ_TYPE_LEVEL_HIGH>;
 				interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2",
 					"tx-cpu3", "rx-shared", "link";
 				port-id = <1>;
@@ -74,12 +74,12 @@
 			};
 
 			CP110_LABEL(eth2): eth2 {
-				interrupts = <ICU_GRP_NSR 41 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 45 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 49 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 53 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 57 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 127 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <41 IRQ_TYPE_LEVEL_HIGH>,
+					     <45 IRQ_TYPE_LEVEL_HIGH>,
+					     <49 IRQ_TYPE_LEVEL_HIGH>,
+					     <53 IRQ_TYPE_LEVEL_HIGH>,
+					     <57 IRQ_TYPE_LEVEL_HIGH>,
+					     <127 IRQ_TYPE_LEVEL_HIGH>;
 				interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2",
 					"tx-cpu3", "rx-shared", "link";
 				port-id = <2>;
@@ -147,16 +147,20 @@
 		CP110_LABEL(icu): interrupt-controller@1e0000 {
 			compatible = "marvell,cp110-icu", "syscon";
 			reg = <0x1e0000 0x440>;
-			#interrupt-cells = <3>;
-			interrupt-controller;
-			msi-parent = <&gicp>;
+
+			CP110_LABEL(icu_nsr): icu-nsr {
+				compatible = "marvell,cp110-icu-nsr";
+				#interrupt-cells = <2>;
+				interrupt-controller;
+				msi-parent = <&gicp>;
+			};
 		};
 
 		CP110_LABEL(rtc): rtc@284000 {
 			compatible = "marvell,armada-8k-rtc";
 			reg = <0x284000 0x20>, <0x284080 0x24>;
 			reg-names = "rtc", "rtc-soc";
-			interrupts = <ICU_GRP_NSR 77 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <77 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		CP110_LABEL(thermal): thermal@400078 {
@@ -182,10 +186,10 @@
 				#gpio-cells = <2>;
 				gpio-ranges = <&CP110_LABEL(pinctrl) 0 0 32>;
 				interrupt-controller;
-				interrupts = <ICU_GRP_NSR 86 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 85 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 84 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 83 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <86 IRQ_TYPE_LEVEL_HIGH>,
+					     <85 IRQ_TYPE_LEVEL_HIGH>,
+					     <84 IRQ_TYPE_LEVEL_HIGH>,
+					     <83 IRQ_TYPE_LEVEL_HIGH>;
 				status = "disabled";
 			};
 
@@ -197,10 +201,10 @@
 				#gpio-cells = <2>;
 				gpio-ranges = <&CP110_LABEL(pinctrl) 0 32 31>;
 				interrupt-controller;
-				interrupts = <ICU_GRP_NSR 82 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 81 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 80 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 79 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <82 IRQ_TYPE_LEVEL_HIGH>,
+					     <81 IRQ_TYPE_LEVEL_HIGH>,
+					     <80 IRQ_TYPE_LEVEL_HIGH>,
+					     <79 IRQ_TYPE_LEVEL_HIGH>;
 				status = "disabled";
 			};
 		};
@@ -210,7 +214,7 @@
 			"generic-xhci";
 			reg = <0x500000 0x4000>;
 			dma-coherent;
-			interrupts = <ICU_GRP_NSR 106 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <106 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 22>,
 				 <&CP110_LABEL(clk) 1 16>;
@@ -222,7 +226,7 @@
 			"generic-xhci";
 			reg = <0x510000 0x4000>;
 			dma-coherent;
-			interrupts = <ICU_GRP_NSR 105 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <105 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 23>,
 				 <&CP110_LABEL(clk) 1 16>;
@@ -233,7 +237,7 @@
 			compatible = "marvell,armada-8k-ahci",
 			"generic-ahci";
 			reg = <0x540000 0x30000>;
-			interrupts = <ICU_GRP_NSR 107 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&CP110_LABEL(clk) 1 15>,
 				 <&CP110_LABEL(clk) 1 16>;
 			status = "disabled";
@@ -286,7 +290,7 @@
 			reg = <0x701000 0x20>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <ICU_GRP_NSR 120 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <120 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 21>,
 				 <&CP110_LABEL(clk) 1 17>;
@@ -298,7 +302,7 @@
 			reg = <0x701100 0x20>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <ICU_GRP_NSR 121 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <121 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 21>,
 				 <&CP110_LABEL(clk) 1 17>;
@@ -309,7 +313,7 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x702000 0x100>;
 			reg-shift = <2>;
-			interrupts = <ICU_GRP_NSR 122 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <122 IRQ_TYPE_LEVEL_HIGH>;
 			reg-io-width = <1>;
 			clock-names = "baudclk", "apb_pclk";
 			clocks = <&CP110_LABEL(clk) 1 21>,
@@ -321,7 +325,7 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x702100 0x100>;
 			reg-shift = <2>;
-			interrupts = <ICU_GRP_NSR 123 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <123 IRQ_TYPE_LEVEL_HIGH>;
 			reg-io-width = <1>;
 			clock-names = "baudclk", "apb_pclk";
 			clocks = <&CP110_LABEL(clk) 1 21>,
@@ -333,7 +337,7 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x702200 0x100>;
 			reg-shift = <2>;
-			interrupts = <ICU_GRP_NSR 124 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <124 IRQ_TYPE_LEVEL_HIGH>;
 			reg-io-width = <1>;
 			clock-names = "baudclk", "apb_pclk";
 			clocks = <&CP110_LABEL(clk) 1 21>,
@@ -345,7 +349,7 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x702300 0x100>;
 			reg-shift = <2>;
-			interrupts = <ICU_GRP_NSR 125 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <125 IRQ_TYPE_LEVEL_HIGH>;
 			reg-io-width = <1>;
 			clock-names = "baudclk", "apb_pclk";
 			clocks = <&CP110_LABEL(clk) 1 21>,
@@ -364,7 +368,7 @@
 			reg = <0x720000 0x54>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <ICU_GRP_NSR 115 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <115 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 2>,
 				 <&CP110_LABEL(clk) 1 17>;
@@ -376,7 +380,7 @@
 			compatible = "marvell,armada-8k-rng",
 			"inside-secure,safexcel-eip76";
 			reg = <0x760000 0x7d>;
-			interrupts = <ICU_GRP_NSR 95 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <95 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 25>,
 				 <&CP110_LABEL(clk) 1 17>;
@@ -386,7 +390,7 @@
 		CP110_LABEL(sdhci0): sdhci@780000 {
 			compatible = "marvell,armada-cp110-sdhci";
 			reg = <0x780000 0x300>;
-			interrupts = <ICU_GRP_NSR 27 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "axi";
 			clocks = <&CP110_LABEL(clk) 1 4>, <&CP110_LABEL(clk) 1 18>;
 			dma-coherent;
@@ -396,12 +400,12 @@
 		CP110_LABEL(crypto): crypto@800000 {
 			compatible = "inside-secure,safexcel-eip197";
 			reg = <0x800000 0x200000>;
-			interrupts = <ICU_GRP_NSR 87 IRQ_TYPE_LEVEL_HIGH>,
-				<ICU_GRP_NSR 88 IRQ_TYPE_LEVEL_HIGH>,
-				<ICU_GRP_NSR 89 IRQ_TYPE_LEVEL_HIGH>,
-				<ICU_GRP_NSR 90 IRQ_TYPE_LEVEL_HIGH>,
-				<ICU_GRP_NSR 91 IRQ_TYPE_LEVEL_HIGH>,
-				<ICU_GRP_NSR 92 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <87 IRQ_TYPE_LEVEL_HIGH>,
+				     <88 IRQ_TYPE_LEVEL_HIGH>,
+				     <89 IRQ_TYPE_LEVEL_HIGH>,
+				     <90 IRQ_TYPE_LEVEL_HIGH>,
+				     <91 IRQ_TYPE_LEVEL_HIGH>,
+				     <92 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "mem", "ring0", "ring1",
 				"ring2", "ring3", "eip";
 			clock-names = "core", "reg";
@@ -430,8 +434,8 @@
 		/* non-prefetchable memory */
 		0x82000000 0 CP110_PCIEx_MEM_BASE(0) 0  CP110_PCIEx_MEM_BASE(0) 0 0xf00000>;
 		interrupt-map-mask = <0 0 0 0>;
-		interrupt-map = <0 0 0 0 &CP110_LABEL(icu) ICU_GRP_NSR 22 IRQ_TYPE_LEVEL_HIGH>;
-		interrupts = <ICU_GRP_NSR 22 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map = <0 0 0 0 &CP110_LABEL(icu_nsr) 22 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
 		num-lanes = <1>;
 		clock-names = "core", "reg";
 		clocks = <&CP110_LABEL(clk) 1 13>, <&CP110_LABEL(clk) 1 14>;
@@ -457,8 +461,8 @@
 		/* non-prefetchable memory */
 		0x82000000 0 CP110_PCIEx_MEM_BASE(1) 0  CP110_PCIEx_MEM_BASE(1) 0 0xf00000>;
 		interrupt-map-mask = <0 0 0 0>;
-		interrupt-map = <0 0 0 0 &CP110_LABEL(icu) ICU_GRP_NSR 24 IRQ_TYPE_LEVEL_HIGH>;
-		interrupts = <ICU_GRP_NSR 24 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map = <0 0 0 0 &CP110_LABEL(icu_nsr) 24 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
 
 		num-lanes = <1>;
 		clock-names = "core", "reg";
@@ -485,8 +489,8 @@
 		/* non-prefetchable memory */
 		0x82000000 0 CP110_PCIEx_MEM_BASE(2) 0  CP110_PCIEx_MEM_BASE(2) 0 0xf00000>;
 		interrupt-map-mask = <0 0 0 0>;
-		interrupt-map = <0 0 0 0 &CP110_LABEL(icu) ICU_GRP_NSR 23 IRQ_TYPE_LEVEL_HIGH>;
-		interrupts = <ICU_GRP_NSR 23 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map = <0 0 0 0 &CP110_LABEL(icu_nsr) 23 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
 
 		num-lanes = <1>;
 		clock-names = "core", "reg";
-- 
2.14.1

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

* [PATCH 16/17] arm64: dts: marvell: use new bindings for CP110 interrupts
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

Create an ICU subnode for the NSR interrupts. This subnode becomes the
CP110 interrupt parent, removing the need for the ICU_GRP_NSR parameter.
Move all DT110 nodes to use these new bindings.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/boot/dts/marvell/armada-cp110.dtsi | 114 +++++++++++++-------------
 1 file changed, 59 insertions(+), 55 deletions(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
index 9323acdb712f..9a7bc365f5a0 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
@@ -25,7 +25,7 @@
 	#address-cells = <2>;
 	#size-cells = <2>;
 	compatible = "simple-bus";
-	interrupt-parent = <&CP110_LABEL(icu)>;
+	interrupt-parent = <&CP110_LABEL(icu_nsr)>;
 	ranges;
 
 	config-space at CP110_BASE {
@@ -46,12 +46,12 @@
 			dma-coherent;
 
 			CP110_LABEL(eth0): eth0 {
-				interrupts = <ICU_GRP_NSR 39 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 43 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 47 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 51 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 55 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 129 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <39 IRQ_TYPE_LEVEL_HIGH>,
+					     <43 IRQ_TYPE_LEVEL_HIGH>,
+					     <47 IRQ_TYPE_LEVEL_HIGH>,
+					     <51 IRQ_TYPE_LEVEL_HIGH>,
+					     <55 IRQ_TYPE_LEVEL_HIGH>,
+					     <129 IRQ_TYPE_LEVEL_HIGH>;
 				interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2",
 					"tx-cpu3", "rx-shared", "link";
 				port-id = <0>;
@@ -60,12 +60,12 @@
 			};
 
 			CP110_LABEL(eth1): eth1 {
-				interrupts = <ICU_GRP_NSR 40 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 44 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 48 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 52 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 56 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 128 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <40 IRQ_TYPE_LEVEL_HIGH>,
+					     <44 IRQ_TYPE_LEVEL_HIGH>,
+					     <48 IRQ_TYPE_LEVEL_HIGH>,
+					     <52 IRQ_TYPE_LEVEL_HIGH>,
+					     <56 IRQ_TYPE_LEVEL_HIGH>,
+					     <128 IRQ_TYPE_LEVEL_HIGH>;
 				interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2",
 					"tx-cpu3", "rx-shared", "link";
 				port-id = <1>;
@@ -74,12 +74,12 @@
 			};
 
 			CP110_LABEL(eth2): eth2 {
-				interrupts = <ICU_GRP_NSR 41 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 45 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 49 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 53 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 57 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 127 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <41 IRQ_TYPE_LEVEL_HIGH>,
+					     <45 IRQ_TYPE_LEVEL_HIGH>,
+					     <49 IRQ_TYPE_LEVEL_HIGH>,
+					     <53 IRQ_TYPE_LEVEL_HIGH>,
+					     <57 IRQ_TYPE_LEVEL_HIGH>,
+					     <127 IRQ_TYPE_LEVEL_HIGH>;
 				interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2",
 					"tx-cpu3", "rx-shared", "link";
 				port-id = <2>;
@@ -147,16 +147,20 @@
 		CP110_LABEL(icu): interrupt-controller at 1e0000 {
 			compatible = "marvell,cp110-icu", "syscon";
 			reg = <0x1e0000 0x440>;
-			#interrupt-cells = <3>;
-			interrupt-controller;
-			msi-parent = <&gicp>;
+
+			CP110_LABEL(icu_nsr): icu-nsr {
+				compatible = "marvell,cp110-icu-nsr";
+				#interrupt-cells = <2>;
+				interrupt-controller;
+				msi-parent = <&gicp>;
+			};
 		};
 
 		CP110_LABEL(rtc): rtc at 284000 {
 			compatible = "marvell,armada-8k-rtc";
 			reg = <0x284000 0x20>, <0x284080 0x24>;
 			reg-names = "rtc", "rtc-soc";
-			interrupts = <ICU_GRP_NSR 77 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <77 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		CP110_LABEL(thermal): thermal at 400078 {
@@ -182,10 +186,10 @@
 				#gpio-cells = <2>;
 				gpio-ranges = <&CP110_LABEL(pinctrl) 0 0 32>;
 				interrupt-controller;
-				interrupts = <ICU_GRP_NSR 86 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 85 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 84 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 83 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <86 IRQ_TYPE_LEVEL_HIGH>,
+					     <85 IRQ_TYPE_LEVEL_HIGH>,
+					     <84 IRQ_TYPE_LEVEL_HIGH>,
+					     <83 IRQ_TYPE_LEVEL_HIGH>;
 				status = "disabled";
 			};
 
@@ -197,10 +201,10 @@
 				#gpio-cells = <2>;
 				gpio-ranges = <&CP110_LABEL(pinctrl) 0 32 31>;
 				interrupt-controller;
-				interrupts = <ICU_GRP_NSR 82 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 81 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 80 IRQ_TYPE_LEVEL_HIGH>,
-					<ICU_GRP_NSR 79 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <82 IRQ_TYPE_LEVEL_HIGH>,
+					     <81 IRQ_TYPE_LEVEL_HIGH>,
+					     <80 IRQ_TYPE_LEVEL_HIGH>,
+					     <79 IRQ_TYPE_LEVEL_HIGH>;
 				status = "disabled";
 			};
 		};
@@ -210,7 +214,7 @@
 			"generic-xhci";
 			reg = <0x500000 0x4000>;
 			dma-coherent;
-			interrupts = <ICU_GRP_NSR 106 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <106 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 22>,
 				 <&CP110_LABEL(clk) 1 16>;
@@ -222,7 +226,7 @@
 			"generic-xhci";
 			reg = <0x510000 0x4000>;
 			dma-coherent;
-			interrupts = <ICU_GRP_NSR 105 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <105 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 23>,
 				 <&CP110_LABEL(clk) 1 16>;
@@ -233,7 +237,7 @@
 			compatible = "marvell,armada-8k-ahci",
 			"generic-ahci";
 			reg = <0x540000 0x30000>;
-			interrupts = <ICU_GRP_NSR 107 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&CP110_LABEL(clk) 1 15>,
 				 <&CP110_LABEL(clk) 1 16>;
 			status = "disabled";
@@ -286,7 +290,7 @@
 			reg = <0x701000 0x20>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <ICU_GRP_NSR 120 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <120 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 21>,
 				 <&CP110_LABEL(clk) 1 17>;
@@ -298,7 +302,7 @@
 			reg = <0x701100 0x20>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <ICU_GRP_NSR 121 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <121 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 21>,
 				 <&CP110_LABEL(clk) 1 17>;
@@ -309,7 +313,7 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x702000 0x100>;
 			reg-shift = <2>;
-			interrupts = <ICU_GRP_NSR 122 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <122 IRQ_TYPE_LEVEL_HIGH>;
 			reg-io-width = <1>;
 			clock-names = "baudclk", "apb_pclk";
 			clocks = <&CP110_LABEL(clk) 1 21>,
@@ -321,7 +325,7 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x702100 0x100>;
 			reg-shift = <2>;
-			interrupts = <ICU_GRP_NSR 123 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <123 IRQ_TYPE_LEVEL_HIGH>;
 			reg-io-width = <1>;
 			clock-names = "baudclk", "apb_pclk";
 			clocks = <&CP110_LABEL(clk) 1 21>,
@@ -333,7 +337,7 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x702200 0x100>;
 			reg-shift = <2>;
-			interrupts = <ICU_GRP_NSR 124 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <124 IRQ_TYPE_LEVEL_HIGH>;
 			reg-io-width = <1>;
 			clock-names = "baudclk", "apb_pclk";
 			clocks = <&CP110_LABEL(clk) 1 21>,
@@ -345,7 +349,7 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x702300 0x100>;
 			reg-shift = <2>;
-			interrupts = <ICU_GRP_NSR 125 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <125 IRQ_TYPE_LEVEL_HIGH>;
 			reg-io-width = <1>;
 			clock-names = "baudclk", "apb_pclk";
 			clocks = <&CP110_LABEL(clk) 1 21>,
@@ -364,7 +368,7 @@
 			reg = <0x720000 0x54>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <ICU_GRP_NSR 115 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <115 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 2>,
 				 <&CP110_LABEL(clk) 1 17>;
@@ -376,7 +380,7 @@
 			compatible = "marvell,armada-8k-rng",
 			"inside-secure,safexcel-eip76";
 			reg = <0x760000 0x7d>;
-			interrupts = <ICU_GRP_NSR 95 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <95 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "reg";
 			clocks = <&CP110_LABEL(clk) 1 25>,
 				 <&CP110_LABEL(clk) 1 17>;
@@ -386,7 +390,7 @@
 		CP110_LABEL(sdhci0): sdhci at 780000 {
 			compatible = "marvell,armada-cp110-sdhci";
 			reg = <0x780000 0x300>;
-			interrupts = <ICU_GRP_NSR 27 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "core", "axi";
 			clocks = <&CP110_LABEL(clk) 1 4>, <&CP110_LABEL(clk) 1 18>;
 			dma-coherent;
@@ -396,12 +400,12 @@
 		CP110_LABEL(crypto): crypto at 800000 {
 			compatible = "inside-secure,safexcel-eip197";
 			reg = <0x800000 0x200000>;
-			interrupts = <ICU_GRP_NSR 87 IRQ_TYPE_LEVEL_HIGH>,
-				<ICU_GRP_NSR 88 IRQ_TYPE_LEVEL_HIGH>,
-				<ICU_GRP_NSR 89 IRQ_TYPE_LEVEL_HIGH>,
-				<ICU_GRP_NSR 90 IRQ_TYPE_LEVEL_HIGH>,
-				<ICU_GRP_NSR 91 IRQ_TYPE_LEVEL_HIGH>,
-				<ICU_GRP_NSR 92 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <87 IRQ_TYPE_LEVEL_HIGH>,
+				     <88 IRQ_TYPE_LEVEL_HIGH>,
+				     <89 IRQ_TYPE_LEVEL_HIGH>,
+				     <90 IRQ_TYPE_LEVEL_HIGH>,
+				     <91 IRQ_TYPE_LEVEL_HIGH>,
+				     <92 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "mem", "ring0", "ring1",
 				"ring2", "ring3", "eip";
 			clock-names = "core", "reg";
@@ -430,8 +434,8 @@
 		/* non-prefetchable memory */
 		0x82000000 0 CP110_PCIEx_MEM_BASE(0) 0  CP110_PCIEx_MEM_BASE(0) 0 0xf00000>;
 		interrupt-map-mask = <0 0 0 0>;
-		interrupt-map = <0 0 0 0 &CP110_LABEL(icu) ICU_GRP_NSR 22 IRQ_TYPE_LEVEL_HIGH>;
-		interrupts = <ICU_GRP_NSR 22 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map = <0 0 0 0 &CP110_LABEL(icu_nsr) 22 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
 		num-lanes = <1>;
 		clock-names = "core", "reg";
 		clocks = <&CP110_LABEL(clk) 1 13>, <&CP110_LABEL(clk) 1 14>;
@@ -457,8 +461,8 @@
 		/* non-prefetchable memory */
 		0x82000000 0 CP110_PCIEx_MEM_BASE(1) 0  CP110_PCIEx_MEM_BASE(1) 0 0xf00000>;
 		interrupt-map-mask = <0 0 0 0>;
-		interrupt-map = <0 0 0 0 &CP110_LABEL(icu) ICU_GRP_NSR 24 IRQ_TYPE_LEVEL_HIGH>;
-		interrupts = <ICU_GRP_NSR 24 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map = <0 0 0 0 &CP110_LABEL(icu_nsr) 24 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
 
 		num-lanes = <1>;
 		clock-names = "core", "reg";
@@ -485,8 +489,8 @@
 		/* non-prefetchable memory */
 		0x82000000 0 CP110_PCIEx_MEM_BASE(2) 0  CP110_PCIEx_MEM_BASE(2) 0 0xf00000>;
 		interrupt-map-mask = <0 0 0 0>;
-		interrupt-map = <0 0 0 0 &CP110_LABEL(icu) ICU_GRP_NSR 23 IRQ_TYPE_LEVEL_HIGH>;
-		interrupts = <ICU_GRP_NSR 23 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map = <0 0 0 0 &CP110_LABEL(icu_nsr) 23 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
 
 		num-lanes = <1>;
 		clock-names = "core", "reg";
-- 
2.14.1

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

* [PATCH 17/17] arm64: dts: marvell: add CP110 ICU SEI subnode
  2018-04-21 13:55 ` Miquel Raynal
@ 2018-04-21 13:55   ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier
  Cc: Mark Rutland, Andrew Lunn, devicetree, Antoine Tenart,
	Catalin Marinas, Gregory Clement, Haim Boot, Will Deacon,
	Maxime Chevallier, Nadav Haklai, Rob Herring, Thomas Petazzoni,
	Miquel Raynal, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

The ICU handles several interrupt groups, each of them being a subpart
of the ICU node.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/boot/dts/marvell/armada-cp110.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
index 9a7bc365f5a0..8e989c721b4c 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
@@ -154,6 +154,13 @@
 				interrupt-controller;
 				msi-parent = <&gicp>;
 			};
+
+			CP110_LABEL(icu_sei): icu-sei {
+				compatible = "marvell,cp110-icu-sei";
+				#interrupt-cells = <2>;
+				interrupt-controller;
+				msi-parent = <&sei>;
+			};
 		};
 
 		CP110_LABEL(rtc): rtc@284000 {
-- 
2.14.1

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

* [PATCH 17/17] arm64: dts: marvell: add CP110 ICU SEI subnode
@ 2018-04-21 13:55   ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-21 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

The ICU handles several interrupt groups, each of them being a subpart
of the ICU node.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm64/boot/dts/marvell/armada-cp110.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
index 9a7bc365f5a0..8e989c721b4c 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
@@ -154,6 +154,13 @@
 				interrupt-controller;
 				msi-parent = <&gicp>;
 			};
+
+			CP110_LABEL(icu_sei): icu-sei {
+				compatible = "marvell,cp110-icu-sei";
+				#interrupt-cells = <2>;
+				interrupt-controller;
+				msi-parent = <&sei>;
+			};
 		};
 
 		CP110_LABEL(rtc): rtc at 284000 {
-- 
2.14.1

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

* Re: [PATCH 01/17] dt-bindings/interrupt-controller: fix Marvell ICU length in the example
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-27 20:16     ` Rob Herring
  -1 siblings, 0 replies; 92+ messages in thread
From: Rob Herring @ 2018-04-27 20:16 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Thomas Petazzoni, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

On Sat, Apr 21, 2018 at 03:55:21PM +0200, Miquel Raynal wrote:
> ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
> specification).
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Reviewed-by: Rob Herring <robh@kernel.org>

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

* [PATCH 01/17] dt-bindings/interrupt-controller: fix Marvell ICU length in the example
@ 2018-04-27 20:16     ` Rob Herring
  0 siblings, 0 replies; 92+ messages in thread
From: Rob Herring @ 2018-04-27 20:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Apr 21, 2018 at 03:55:21PM +0200, Miquel Raynal wrote:
> ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
> specification).
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Reviewed-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH 13/17] dt-bindings/interrupt-controller: update Marvell ICU bindings
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-27 20:47     ` Rob Herring
  -1 siblings, 0 replies; 92+ messages in thread
From: Rob Herring @ 2018-04-27 20:47 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Thomas Petazzoni, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

On Sat, Apr 21, 2018 at 03:55:33PM +0200, Miquel Raynal wrote:
> Change the documentation to reflect the new bindings used for Marvell
> ICU. This involves describing each interrupt group as a subnode of the
> ICU node. Each of them having their own compatible.

Why?

This breaks compatibility.

> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  .../bindings/interrupt-controller/marvell,icu.txt  | 60 ++++++++++++++++------
>  1 file changed, 43 insertions(+), 17 deletions(-)

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

* [PATCH 13/17] dt-bindings/interrupt-controller: update Marvell ICU bindings
@ 2018-04-27 20:47     ` Rob Herring
  0 siblings, 0 replies; 92+ messages in thread
From: Rob Herring @ 2018-04-27 20:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Apr 21, 2018 at 03:55:33PM +0200, Miquel Raynal wrote:
> Change the documentation to reflect the new bindings used for Marvell
> ICU. This involves describing each interrupt group as a subnode of the
> ICU node. Each of them having their own compatible.

Why?

This breaks compatibility.

> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  .../bindings/interrupt-controller/marvell,icu.txt  | 60 ++++++++++++++++------
>  1 file changed, 43 insertions(+), 17 deletions(-)

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

* Re: [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-27 20:50     ` Rob Herring
  -1 siblings, 0 replies; 92+ messages in thread
From: Rob Herring @ 2018-04-27 20:50 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Thomas Petazzoni, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

On Sat, Apr 21, 2018 at 03:55:34PM +0200, Miquel Raynal wrote:
> Describe the SEI (System Error Interrupt) controller driver. The
> controller is part of the GIC. It aggregates two types of interrupts,
> wired and MSIs from respectively the AP and the CPs, into a single SPI
> interrupt.
> 
> Suggested-by: Haim Boot <hayim@marvell.com>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  .../bindings/interrupt-controller/marvell,sei.txt  | 54 ++++++++++++++++++++++
>  1 file changed, 54 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> 
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> new file mode 100644
> index 000000000000..a246d59552b1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> @@ -0,0 +1,54 @@
> +Marvell SEI (System Error Interrupt) Controller
> +-----------------------------------------------
> +
> +Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
> +It receives interrupts from several sources and aggregates them to a single
> +interrupt line (an SPI) on the primary interrupt controller.
> +
> +The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is
> +wired while a second set comes from the CPs by the mean of MSIs. Each
> +'domain' is represented as a subnode.
> +
> +Required properties:
> +
> +- compatible: should be "marvell,armada-8k-sei".
> +- reg: SEI registers location and length.
> +- interrupts: identifies the parent IRQ that will be triggered.
> +- #address-cells: should be '1', represents the position of the first
> +                  IRQ of a given type in the SEI range.
> +- #size-cells: should be '1', represents the number of a given type of
> +               IRQs.
> +
> +Child node 'sei-wired-controller' required properties:
> +
> +- reg: the range of wired interrupts.
> +- #interrupt-cells: number of cells to define an SEI wired interrupt
> +                    coming from the AP, should be 1. The cell is the IRQ
> +                    number.
> +- interrupt-controller: identifies the node as an interrupt controller.
> +
> +Child node 'sei-msi-controller' required properties:
> +
> +- reg: the range of non-wired interrupts triggered by way of MSIs.
> +- msi-controller: identifies the node as an MSI controller.
> +
> +Example:
> +
> +        sei: sei@3f0200 {
> +               compatible = "marvell,armada-8k-sei";
> +               reg = <0x3f0200 0x40>;
> +               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +
> +               sei_wired_controller: sei-wired-controller@0 {
> +                       reg = <0 21>;

Using interrupt numbers in reg is strange.

> +                       #interrupt-cells = <1>;
> +                       interrupt-controller;
> +               };
> +
> +               sei_msi_controller: sei-msi-controller@21 {
> +                       reg = <21 43>;
> +                       msi-controller;

Can't the parent be both an interrupt-controller and msi-controller?

> +               };
> +       };
> -- 
> 2.14.1
> 

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

* [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
@ 2018-04-27 20:50     ` Rob Herring
  0 siblings, 0 replies; 92+ messages in thread
From: Rob Herring @ 2018-04-27 20:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Apr 21, 2018 at 03:55:34PM +0200, Miquel Raynal wrote:
> Describe the SEI (System Error Interrupt) controller driver. The
> controller is part of the GIC. It aggregates two types of interrupts,
> wired and MSIs from respectively the AP and the CPs, into a single SPI
> interrupt.
> 
> Suggested-by: Haim Boot <hayim@marvell.com>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  .../bindings/interrupt-controller/marvell,sei.txt  | 54 ++++++++++++++++++++++
>  1 file changed, 54 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> 
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> new file mode 100644
> index 000000000000..a246d59552b1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> @@ -0,0 +1,54 @@
> +Marvell SEI (System Error Interrupt) Controller
> +-----------------------------------------------
> +
> +Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
> +It receives interrupts from several sources and aggregates them to a single
> +interrupt line (an SPI) on the primary interrupt controller.
> +
> +The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is
> +wired while a second set comes from the CPs by the mean of MSIs. Each
> +'domain' is represented as a subnode.
> +
> +Required properties:
> +
> +- compatible: should be "marvell,armada-8k-sei".
> +- reg: SEI registers location and length.
> +- interrupts: identifies the parent IRQ that will be triggered.
> +- #address-cells: should be '1', represents the position of the first
> +                  IRQ of a given type in the SEI range.
> +- #size-cells: should be '1', represents the number of a given type of
> +               IRQs.
> +
> +Child node 'sei-wired-controller' required properties:
> +
> +- reg: the range of wired interrupts.
> +- #interrupt-cells: number of cells to define an SEI wired interrupt
> +                    coming from the AP, should be 1. The cell is the IRQ
> +                    number.
> +- interrupt-controller: identifies the node as an interrupt controller.
> +
> +Child node 'sei-msi-controller' required properties:
> +
> +- reg: the range of non-wired interrupts triggered by way of MSIs.
> +- msi-controller: identifies the node as an MSI controller.
> +
> +Example:
> +
> +        sei: sei at 3f0200 {
> +               compatible = "marvell,armada-8k-sei";
> +               reg = <0x3f0200 0x40>;
> +               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +
> +               sei_wired_controller: sei-wired-controller at 0 {
> +                       reg = <0 21>;

Using interrupt numbers in reg is strange.

> +                       #interrupt-cells = <1>;
> +                       interrupt-controller;
> +               };
> +
> +               sei_msi_controller: sei-msi-controller at 21 {
> +                       reg = <21 43>;
> +                       msi-controller;

Can't the parent be both an interrupt-controller and msi-controller?

> +               };
> +       };
> -- 
> 2.14.1
> 

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

* Re: [PATCH 13/17] dt-bindings/interrupt-controller: update Marvell ICU bindings
  2018-04-27 20:47     ` Rob Herring
@ 2018-04-28 10:42       ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-28 10:42 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Thomas Petazzoni, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hi Rob,

On Fri, 27 Apr 2018 15:47:23 -0500, Rob Herring <robh@kernel.org> wrote:

> On Sat, Apr 21, 2018 at 03:55:33PM +0200, Miquel Raynal wrote:
> > Change the documentation to reflect the new bindings used for Marvell
> > ICU. This involves describing each interrupt group as a subnode of the
> > ICU node. Each of them having their own compatible.  
> 
> Why?
> 
> This breaks compatibility.

It does indeed.

The problem comes from the inability to handle multiple MSI parents
for one device and the fact that the API was not designed in this way
at all. I would not risk myself to explain the MSI arcana but I suggest
you to have a look at this thread which led to this series:

https://www.spinics.net/lists/arm-kernel/msg645115.html

Of course I am open to suggestions.

Thanks,
Miquèl
 
> 
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  .../bindings/interrupt-controller/marvell,icu.txt  | 60 ++++++++++++++++------
> >  1 file changed, 43 insertions(+), 17 deletions(-)  



-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 13/17] dt-bindings/interrupt-controller: update Marvell ICU bindings
@ 2018-04-28 10:42       ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-28 10:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Rob,

On Fri, 27 Apr 2018 15:47:23 -0500, Rob Herring <robh@kernel.org> wrote:

> On Sat, Apr 21, 2018 at 03:55:33PM +0200, Miquel Raynal wrote:
> > Change the documentation to reflect the new bindings used for Marvell
> > ICU. This involves describing each interrupt group as a subnode of the
> > ICU node. Each of them having their own compatible.  
> 
> Why?
> 
> This breaks compatibility.

It does indeed.

The problem comes from the inability to handle multiple MSI parents
for one device and the fact that the API was not designed in this way
at all. I would not risk myself to explain the MSI arcana but I suggest
you to have a look at this thread which led to this series:

https://www.spinics.net/lists/arm-kernel/msg645115.html

Of course I am open to suggestions.

Thanks,
Miqu?l
 
> 
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  .../bindings/interrupt-controller/marvell,icu.txt  | 60 ++++++++++++++++------
> >  1 file changed, 43 insertions(+), 17 deletions(-)  



-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
  2018-04-27 20:50     ` Rob Herring
@ 2018-04-28 10:48       ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-28 10:48 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Thomas Petazzoni, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hi Rob,

On Fri, 27 Apr 2018 15:50:32 -0500, Rob Herring <robh@kernel.org> wrote:

> On Sat, Apr 21, 2018 at 03:55:34PM +0200, Miquel Raynal wrote:
> > Describe the SEI (System Error Interrupt) controller driver. The
> > controller is part of the GIC. It aggregates two types of interrupts,
> > wired and MSIs from respectively the AP and the CPs, into a single SPI
> > interrupt.
> > 
> > Suggested-by: Haim Boot <hayim@marvell.com>
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  .../bindings/interrupt-controller/marvell,sei.txt  | 54 ++++++++++++++++++++++
> >  1 file changed, 54 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> > new file mode 100644
> > index 000000000000..a246d59552b1
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> > @@ -0,0 +1,54 @@
> > +Marvell SEI (System Error Interrupt) Controller
> > +-----------------------------------------------
> > +
> > +Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
> > +It receives interrupts from several sources and aggregates them to a single
> > +interrupt line (an SPI) on the primary interrupt controller.
> > +
> > +The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is
> > +wired while a second set comes from the CPs by the mean of MSIs. Each
> > +'domain' is represented as a subnode.
> > +
> > +Required properties:
> > +
> > +- compatible: should be "marvell,armada-8k-sei".
> > +- reg: SEI registers location and length.
> > +- interrupts: identifies the parent IRQ that will be triggered.
> > +- #address-cells: should be '1', represents the position of the first
> > +                  IRQ of a given type in the SEI range.
> > +- #size-cells: should be '1', represents the number of a given type of
> > +               IRQs.
> > +
> > +Child node 'sei-wired-controller' required properties:
> > +
> > +- reg: the range of wired interrupts.
> > +- #interrupt-cells: number of cells to define an SEI wired interrupt
> > +                    coming from the AP, should be 1. The cell is the IRQ
> > +                    number.
> > +- interrupt-controller: identifies the node as an interrupt controller.
> > +
> > +Child node 'sei-msi-controller' required properties:
> > +
> > +- reg: the range of non-wired interrupts triggered by way of MSIs.
> > +- msi-controller: identifies the node as an MSI controller.
> > +
> > +Example:
> > +
> > +        sei: sei@3f0200 {
> > +               compatible = "marvell,armada-8k-sei";
> > +               reg = <0x3f0200 0x40>;
> > +               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
> > +               #address-cells = <1>;
> > +               #size-cells = <1>;
> > +
> > +               sei_wired_controller: sei-wired-controller@0 {
> > +                       reg = <0 21>;  
> 
> Using interrupt numbers in reg is strange.

I thought the reg property was the one to choose here, I can of course
change it, what would you suggest?

> 
> > +                       #interrupt-cells = <1>;
> > +                       interrupt-controller;
> > +               };
> > +
> > +               sei_msi_controller: sei-msi-controller@21 {
> > +                       reg = <21 43>;
> > +                       msi-controller;  
> 
> Can't the parent be both an interrupt-controller and msi-controller?

We need to know which one aggregates interrupts, which one receives
MSIs and most importantly which interrupt is what (within the 64
that are handled by the SEI).

I thought it would describe the hardware pretty well, do you think to
another solution?
 
> 
> > +               };
> > +       };
> > -- 
> > 2.14.1
> >   

Thanks,
Miquèl

-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
@ 2018-04-28 10:48       ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-04-28 10:48 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Rob,

On Fri, 27 Apr 2018 15:50:32 -0500, Rob Herring <robh@kernel.org> wrote:

> On Sat, Apr 21, 2018 at 03:55:34PM +0200, Miquel Raynal wrote:
> > Describe the SEI (System Error Interrupt) controller driver. The
> > controller is part of the GIC. It aggregates two types of interrupts,
> > wired and MSIs from respectively the AP and the CPs, into a single SPI
> > interrupt.
> > 
> > Suggested-by: Haim Boot <hayim@marvell.com>
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  .../bindings/interrupt-controller/marvell,sei.txt  | 54 ++++++++++++++++++++++
> >  1 file changed, 54 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> > new file mode 100644
> > index 000000000000..a246d59552b1
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> > @@ -0,0 +1,54 @@
> > +Marvell SEI (System Error Interrupt) Controller
> > +-----------------------------------------------
> > +
> > +Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
> > +It receives interrupts from several sources and aggregates them to a single
> > +interrupt line (an SPI) on the primary interrupt controller.
> > +
> > +The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is
> > +wired while a second set comes from the CPs by the mean of MSIs. Each
> > +'domain' is represented as a subnode.
> > +
> > +Required properties:
> > +
> > +- compatible: should be "marvell,armada-8k-sei".
> > +- reg: SEI registers location and length.
> > +- interrupts: identifies the parent IRQ that will be triggered.
> > +- #address-cells: should be '1', represents the position of the first
> > +                  IRQ of a given type in the SEI range.
> > +- #size-cells: should be '1', represents the number of a given type of
> > +               IRQs.
> > +
> > +Child node 'sei-wired-controller' required properties:
> > +
> > +- reg: the range of wired interrupts.
> > +- #interrupt-cells: number of cells to define an SEI wired interrupt
> > +                    coming from the AP, should be 1. The cell is the IRQ
> > +                    number.
> > +- interrupt-controller: identifies the node as an interrupt controller.
> > +
> > +Child node 'sei-msi-controller' required properties:
> > +
> > +- reg: the range of non-wired interrupts triggered by way of MSIs.
> > +- msi-controller: identifies the node as an MSI controller.
> > +
> > +Example:
> > +
> > +        sei: sei at 3f0200 {
> > +               compatible = "marvell,armada-8k-sei";
> > +               reg = <0x3f0200 0x40>;
> > +               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
> > +               #address-cells = <1>;
> > +               #size-cells = <1>;
> > +
> > +               sei_wired_controller: sei-wired-controller at 0 {
> > +                       reg = <0 21>;  
> 
> Using interrupt numbers in reg is strange.

I thought the reg property was the one to choose here, I can of course
change it, what would you suggest?

> 
> > +                       #interrupt-cells = <1>;
> > +                       interrupt-controller;
> > +               };
> > +
> > +               sei_msi_controller: sei-msi-controller at 21 {
> > +                       reg = <21 43>;
> > +                       msi-controller;  
> 
> Can't the parent be both an interrupt-controller and msi-controller?

We need to know which one aggregates interrupts, which one receives
MSIs and most importantly which interrupt is what (within the 64
that are handled by the SEI).

I thought it would describe the hardware pretty well, do you think to
another solution?
 
> 
> > +               };
> > +       };
> > -- 
> > 2.14.1
> >   

Thanks,
Miqu?l

-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 13/17] dt-bindings/interrupt-controller: update Marvell ICU bindings
  2018-04-28 10:42       ` Miquel Raynal
@ 2018-04-28 10:50         ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-28 10:50 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Rob Herring, Jason Cooper, Andrew Lunn,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	devicetree, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

On Sat, 28 Apr 2018 12:42:04 +0200, Miquel Raynal wrote:

> On Fri, 27 Apr 2018 15:47:23 -0500, Rob Herring <robh@kernel.org> wrote:
> 
> > On Sat, Apr 21, 2018 at 03:55:33PM +0200, Miquel Raynal wrote:  
> > > Change the documentation to reflect the new bindings used for Marvell
> > > ICU. This involves describing each interrupt group as a subnode of the
> > > ICU node. Each of them having their own compatible.    
> > 
> > Why?
> > 
> > This breaks compatibility.  
> 
> It does indeed.

Well, yes and no: your driver supports both the old and new binding, so
the compatibility is not broken. So, yes the binding is changed in an
incompatible way, but the driver continues to support the old binding.

Perhaps the binding documentation should continue to document the
legacy binding, mark it as still supported but deprecated.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* [PATCH 13/17] dt-bindings/interrupt-controller: update Marvell ICU bindings
@ 2018-04-28 10:50         ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-28 10:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Sat, 28 Apr 2018 12:42:04 +0200, Miquel Raynal wrote:

> On Fri, 27 Apr 2018 15:47:23 -0500, Rob Herring <robh@kernel.org> wrote:
> 
> > On Sat, Apr 21, 2018 at 03:55:33PM +0200, Miquel Raynal wrote:  
> > > Change the documentation to reflect the new bindings used for Marvell
> > > ICU. This involves describing each interrupt group as a subnode of the
> > > ICU node. Each of them having their own compatible.    
> > 
> > Why?
> > 
> > This breaks compatibility.  
> 
> It does indeed.

Well, yes and no: your driver supports both the old and new binding, so
the compatibility is not broken. So, yes the binding is changed in an
incompatible way, but the driver continues to support the old binding.

Perhaps the binding documentation should continue to document the
legacy binding, mark it as still supported but deprecated.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 02/17] arm64: dts: marvell: fix CP110 ICU node size
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-30 12:38     ` Gregory CLEMENT
  -1 siblings, 0 replies; 92+ messages in thread
From: Gregory CLEMENT @ 2018-04-30 12:38 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Hanna Hawa, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Petazzoni, Thomas Gleixner, linux-arm-kernel,
	Sebastian Hesselbarth

Hi Miquel,
 
 On sam., avril 21 2018, Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
> specification).
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

This patch looks like a fix, could you resubmit it with the approriate
flags?

Thanks,

Gregory

> ---
>  arch/arm64/boot/dts/marvell/armada-cp110.dtsi | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
> index 48cad7919efa..9fa41c54f69c 100644
> --- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
> +++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
> @@ -146,7 +146,7 @@
>  
>  		CP110_LABEL(icu): interrupt-controller@1e0000 {
>  			compatible = "marvell,cp110-icu";
> -			reg = <0x1e0000 0x10>;
> +			reg = <0x1e0000 0x440>;
>  			#interrupt-cells = <3>;
>  			interrupt-controller;
>  			msi-parent = <&gicp>;
> -- 
> 2.14.1
>

-- 
Gregory Clement, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
http://bootlin.com

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

* [PATCH 02/17] arm64: dts: marvell: fix CP110 ICU node size
@ 2018-04-30 12:38     ` Gregory CLEMENT
  0 siblings, 0 replies; 92+ messages in thread
From: Gregory CLEMENT @ 2018-04-30 12:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Miquel,
 
 On sam., avril 21 2018, Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
> specification).
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

This patch looks like a fix, could you resubmit it with the approriate
flags?

Thanks,

Gregory

> ---
>  arch/arm64/boot/dts/marvell/armada-cp110.dtsi | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
> index 48cad7919efa..9fa41c54f69c 100644
> --- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
> +++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
> @@ -146,7 +146,7 @@
>  
>  		CP110_LABEL(icu): interrupt-controller at 1e0000 {
>  			compatible = "marvell,cp110-icu";
> -			reg = <0x1e0000 0x10>;
> +			reg = <0x1e0000 0x440>;
>  			#interrupt-cells = <3>;
>  			interrupt-controller;
>  			msi-parent = <&gicp>;
> -- 
> 2.14.1
>

-- 
Gregory Clement, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
http://bootlin.com

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

* Re: [PATCH 06/17] irqchip/irq-mvebu-icu: switch to regmap
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-30 12:42     ` Gregory CLEMENT
  -1 siblings, 0 replies; 92+ messages in thread
From: Gregory CLEMENT @ 2018-04-30 12:42 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Hanna Hawa, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Petazzoni, Thomas Gleixner, linux-arm-kernel,
	Sebastian Hesselbarth

Hi Miquel,
 
 On sam., avril 21 2018, Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> The ICU DT nodes have now the 'syscon' compatible, we can switch to
> regmap before splitting the code to support multiple platform devices to
> be probed (one for the ICU, one per interrupt group).
>

How do you handle the case when you receive an old dtb (without the
syscon compatible) ?

Gregory

> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/irqchip/irq-mvebu-icu.c | 37 ++++++++++++++++++++-----------------
>  1 file changed, 20 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
> index 5af2520445c4..580586240781 100644
> --- a/drivers/irqchip/irq-mvebu-icu.c
> +++ b/drivers/irqchip/irq-mvebu-icu.c
> @@ -18,6 +18,8 @@
>  #include <linux/of_irq.h>
>  #include <linux/of_platform.h>
>  #include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
>  
>  #include <dt-bindings/interrupt-controller/mvebu-icu.h>
>  
> @@ -40,7 +42,7 @@
>  
>  struct mvebu_icu {
>  	struct irq_chip irq_chip;
> -	void __iomem *base;
> +	struct regmap *regmap;
>  	struct irq_domain *domain;
>  	struct device *dev;
>  };
> @@ -69,7 +71,7 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
>  		icu_int = 0;
>  	}
>  
> -	writel_relaxed(icu_int, icu->base + ICU_INT_CFG(d->hwirq));
> +	regmap_write(icu->regmap, ICU_INT_CFG(d->hwirq), icu_int);
>  
>  	/*
>  	 * The SATA unit has 2 ports, and a dedicated ICU entry per
> @@ -81,10 +83,10 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
>  	 * configured (regardless of which port is actually in use).
>  	 */
>  	if (d->hwirq == ICU_SATA0_ICU_ID || d->hwirq == ICU_SATA1_ICU_ID) {
> -		writel_relaxed(icu_int,
> -			       icu->base + ICU_INT_CFG(ICU_SATA0_ICU_ID));
> -		writel_relaxed(icu_int,
> -			       icu->base + ICU_INT_CFG(ICU_SATA1_ICU_ID));
> +		regmap_write(icu->regmap, ICU_INT_CFG(ICU_SATA0_ICU_ID),
> +			     icu_int);
> +		regmap_write(icu->regmap, ICU_INT_CFG(ICU_SATA1_ICU_ID),
> +			     icu_int);
>  	}
>  }
>  
> @@ -208,12 +210,13 @@ static int mvebu_icu_probe(struct platform_device *pdev)
>  
>  	icu->dev = &pdev->dev;
>  
> +	icu->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, NULL);
> +	if (IS_ERR(icu->regmap))
> +		return PTR_ERR(icu->regmap);
> +
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	icu->base = devm_ioremap_resource(&pdev->dev, res);
> -	if (IS_ERR(icu->base)) {
> -		dev_err(&pdev->dev, "Failed to map icu base address.\n");
> -		return PTR_ERR(icu->base);
> -	}
> +	if (!res)
> +		return -ENODEV;
>  
>  	icu->irq_chip.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
>  					    "ICU.%x",
> @@ -247,10 +250,10 @@ static int mvebu_icu_probe(struct platform_device *pdev)
>  		return ret;
>  
>  	/* Set Clear/Set ICU SPI message address in AP */
> -	writel_relaxed(upper_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AH);
> -	writel_relaxed(lower_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AL);
> -	writel_relaxed(upper_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AH);
> -	writel_relaxed(lower_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AL);
> +	regmap_write(icu->regmap, ICU_SETSPI_NSR_AH, upper_32_bits(setspi));
> +	regmap_write(icu->regmap, ICU_SETSPI_NSR_AL, lower_32_bits(setspi));
> +	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AH, upper_32_bits(clrspi));
> +	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AL, lower_32_bits(clrspi));
>  
>  	/*
>  	 * Clean all ICU interrupts with type SPI_NSR, required to
> @@ -259,11 +262,11 @@ static int mvebu_icu_probe(struct platform_device *pdev)
>  	for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
>  		u32 icu_int, icu_grp;
>  
> -		icu_int = readl(icu->base + ICU_INT_CFG(i));
> +		regmap_read(icu->regmap, ICU_INT_CFG(i), &icu_int);
>  		icu_grp = icu_int >> ICU_GROUP_SHIFT;
>  
>  		if (icu_grp == ICU_GRP_NSR)
> -			writel_relaxed(0x0, icu->base + ICU_INT_CFG(i));
> +			regmap_write(icu->regmap, ICU_INT_CFG(i), 0);
>  	}
>  
>  	icu->domain =
> -- 
> 2.14.1
>

-- 
Gregory Clement, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
http://bootlin.com

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

* [PATCH 06/17] irqchip/irq-mvebu-icu: switch to regmap
@ 2018-04-30 12:42     ` Gregory CLEMENT
  0 siblings, 0 replies; 92+ messages in thread
From: Gregory CLEMENT @ 2018-04-30 12:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Miquel,
 
 On sam., avril 21 2018, Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> The ICU DT nodes have now the 'syscon' compatible, we can switch to
> regmap before splitting the code to support multiple platform devices to
> be probed (one for the ICU, one per interrupt group).
>

How do you handle the case when you receive an old dtb (without the
syscon compatible) ?

Gregory

> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/irqchip/irq-mvebu-icu.c | 37 ++++++++++++++++++++-----------------
>  1 file changed, 20 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
> index 5af2520445c4..580586240781 100644
> --- a/drivers/irqchip/irq-mvebu-icu.c
> +++ b/drivers/irqchip/irq-mvebu-icu.c
> @@ -18,6 +18,8 @@
>  #include <linux/of_irq.h>
>  #include <linux/of_platform.h>
>  #include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
>  
>  #include <dt-bindings/interrupt-controller/mvebu-icu.h>
>  
> @@ -40,7 +42,7 @@
>  
>  struct mvebu_icu {
>  	struct irq_chip irq_chip;
> -	void __iomem *base;
> +	struct regmap *regmap;
>  	struct irq_domain *domain;
>  	struct device *dev;
>  };
> @@ -69,7 +71,7 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
>  		icu_int = 0;
>  	}
>  
> -	writel_relaxed(icu_int, icu->base + ICU_INT_CFG(d->hwirq));
> +	regmap_write(icu->regmap, ICU_INT_CFG(d->hwirq), icu_int);
>  
>  	/*
>  	 * The SATA unit has 2 ports, and a dedicated ICU entry per
> @@ -81,10 +83,10 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
>  	 * configured (regardless of which port is actually in use).
>  	 */
>  	if (d->hwirq == ICU_SATA0_ICU_ID || d->hwirq == ICU_SATA1_ICU_ID) {
> -		writel_relaxed(icu_int,
> -			       icu->base + ICU_INT_CFG(ICU_SATA0_ICU_ID));
> -		writel_relaxed(icu_int,
> -			       icu->base + ICU_INT_CFG(ICU_SATA1_ICU_ID));
> +		regmap_write(icu->regmap, ICU_INT_CFG(ICU_SATA0_ICU_ID),
> +			     icu_int);
> +		regmap_write(icu->regmap, ICU_INT_CFG(ICU_SATA1_ICU_ID),
> +			     icu_int);
>  	}
>  }
>  
> @@ -208,12 +210,13 @@ static int mvebu_icu_probe(struct platform_device *pdev)
>  
>  	icu->dev = &pdev->dev;
>  
> +	icu->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, NULL);
> +	if (IS_ERR(icu->regmap))
> +		return PTR_ERR(icu->regmap);
> +
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	icu->base = devm_ioremap_resource(&pdev->dev, res);
> -	if (IS_ERR(icu->base)) {
> -		dev_err(&pdev->dev, "Failed to map icu base address.\n");
> -		return PTR_ERR(icu->base);
> -	}
> +	if (!res)
> +		return -ENODEV;
>  
>  	icu->irq_chip.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
>  					    "ICU.%x",
> @@ -247,10 +250,10 @@ static int mvebu_icu_probe(struct platform_device *pdev)
>  		return ret;
>  
>  	/* Set Clear/Set ICU SPI message address in AP */
> -	writel_relaxed(upper_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AH);
> -	writel_relaxed(lower_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AL);
> -	writel_relaxed(upper_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AH);
> -	writel_relaxed(lower_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AL);
> +	regmap_write(icu->regmap, ICU_SETSPI_NSR_AH, upper_32_bits(setspi));
> +	regmap_write(icu->regmap, ICU_SETSPI_NSR_AL, lower_32_bits(setspi));
> +	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AH, upper_32_bits(clrspi));
> +	regmap_write(icu->regmap, ICU_CLRSPI_NSR_AL, lower_32_bits(clrspi));
>  
>  	/*
>  	 * Clean all ICU interrupts with type SPI_NSR, required to
> @@ -259,11 +262,11 @@ static int mvebu_icu_probe(struct platform_device *pdev)
>  	for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
>  		u32 icu_int, icu_grp;
>  
> -		icu_int = readl(icu->base + ICU_INT_CFG(i));
> +		regmap_read(icu->regmap, ICU_INT_CFG(i), &icu_int);
>  		icu_grp = icu_int >> ICU_GROUP_SHIFT;
>  
>  		if (icu_grp == ICU_GRP_NSR)
> -			writel_relaxed(0x0, icu->base + ICU_INT_CFG(i));
> +			regmap_write(icu->regmap, ICU_INT_CFG(i), 0);
>  	}
>  
>  	icu->domain =
> -- 
> 2.14.1
>

-- 
Gregory Clement, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
http://bootlin.com

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

* Re: [PATCH 11/17] arm64: marvell: enable SEI driver
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-30 13:01     ` Gregory CLEMENT
  -1 siblings, 0 replies; 92+ messages in thread
From: Gregory CLEMENT @ 2018-04-30 13:01 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, devicetree, Jason Cooper, Andrew Lunn,
	Marc Zyngier, Catalin Marinas, Hanna Hawa, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Petazzoni, Thomas Gleixner, linux-arm-kernel,
	Sebastian Hesselbarth

Hi Miquel,
 
 On sam., avril 21 2018, Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Enable the newly introduced Marvell SEI driver for the 64-bit Marvell
> EBU platforms.
>
> Suggested-by: Haim Boot <hayim@marvell.com>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Reviewed-by: Gregory CLEMENT <gregory.clement@bootlin.com>

Once the driver will be accepted, I will apply this patch on mvebu/arm64

Thanks,

Gregory


> ---
>  arch/arm64/Kconfig.platforms | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
> index 2b1535cdeb7c..dc3c42938051 100644
> --- a/arch/arm64/Kconfig.platforms
> +++ b/arch/arm64/Kconfig.platforms
> @@ -121,6 +121,7 @@ config ARCH_MVEBU
>  	select MVEBU_ICU
>  	select MVEBU_ODMI
>  	select MVEBU_PIC
> +	select MVEBU_SEI
>  	select OF_GPIO
>  	select PINCTRL
>  	select PINCTRL_ARMADA_37XX
> -- 
> 2.14.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
Gregory Clement, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
http://bootlin.com

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

* [PATCH 11/17] arm64: marvell: enable SEI driver
@ 2018-04-30 13:01     ` Gregory CLEMENT
  0 siblings, 0 replies; 92+ messages in thread
From: Gregory CLEMENT @ 2018-04-30 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Miquel,
 
 On sam., avril 21 2018, Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Enable the newly introduced Marvell SEI driver for the 64-bit Marvell
> EBU platforms.
>
> Suggested-by: Haim Boot <hayim@marvell.com>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Reviewed-by: Gregory CLEMENT <gregory.clement@bootlin.com>

Once the driver will be accepted, I will apply this patch on mvebu/arm64

Thanks,

Gregory


> ---
>  arch/arm64/Kconfig.platforms | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
> index 2b1535cdeb7c..dc3c42938051 100644
> --- a/arch/arm64/Kconfig.platforms
> +++ b/arch/arm64/Kconfig.platforms
> @@ -121,6 +121,7 @@ config ARCH_MVEBU
>  	select MVEBU_ICU
>  	select MVEBU_ODMI
>  	select MVEBU_PIC
> +	select MVEBU_SEI
>  	select OF_GPIO
>  	select PINCTRL
>  	select PINCTRL_ARMADA_37XX
> -- 
> 2.14.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
Gregory Clement, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
http://bootlin.com

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

* Re: [PATCH 01/17] dt-bindings/interrupt-controller: fix Marvell ICU length in the example
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-30 13:44     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:44 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

On Sat, 21 Apr 2018 15:55:21 +0200, Miquel Raynal wrote:
> ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
> specification).
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* [PATCH 01/17] dt-bindings/interrupt-controller: fix Marvell ICU length in the example
@ 2018-04-30 13:44     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Sat, 21 Apr 2018 15:55:21 +0200, Miquel Raynal wrote:
> ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
> specification).
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 02/17] arm64: dts: marvell: fix CP110 ICU node size
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-30 13:44     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:44 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

On Sat, 21 Apr 2018 15:55:22 +0200, Miquel Raynal wrote:
> ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
> specification).
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* [PATCH 02/17] arm64: dts: marvell: fix CP110 ICU node size
@ 2018-04-30 13:44     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Sat, 21 Apr 2018 15:55:22 +0200, Miquel Raynal wrote:
> ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the
> specification).
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 03/17] arm64: dts: marvell: add syscon compatible to CP110 ICU node
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-30 13:45     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:45 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

On Sat, 21 Apr 2018 15:55:23 +0200, Miquel Raynal wrote:
> Prepare the migration to new bindings where the ICU node has several
> subnodes: one per interrupt group (NSR, SEI, REI, etc). The code for
> each node will share the same set of registers. Turning the ICU node
> into a syscon is a clean solution to handle that.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

In fact, I am wondering if this is really necessary. Can't we instead
just create the regmap() for the ICU MMIO region in the ->probe() of
the parent ICU device ?

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* [PATCH 03/17] arm64: dts: marvell: add syscon compatible to CP110 ICU node
@ 2018-04-30 13:45     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Sat, 21 Apr 2018 15:55:23 +0200, Miquel Raynal wrote:
> Prepare the migration to new bindings where the ICU node has several
> subnodes: one per interrupt group (NSR, SEI, REI, etc). The code for
> each node will share the same set of registers. Turning the ICU node
> into a syscon is a clean solution to handle that.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

In fact, I am wondering if this is really necessary. Can't we instead
just create the regmap() for the ICU MMIO region in the ->probe() of
the parent ICU device ?

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 04/17] irqchip/irq-mvebu-icu: fix wrong user data retrieval
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-30 13:49     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:49 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

In the title, I think "user data" is not really appropriate. "private
date" or "device private data" maybe ?

On Sat, 21 Apr 2018 15:55:24 +0200, Miquel Raynal wrote:
> The irq_domain structure has an host_data pointer that just stores user
> data. It is meant to not be touched by the IRQ core. However, when it
> comes to MSI, the MSI layer adds its own private data there with a
> structure that also has a host_data pointer.
> 
> Because this IRQ domain is an MSI domain, to access user data we should
> do a d->host_data->host_data, also wrapped as
> 'platform_msi_get_host_data()'.
> 
> This bug was lying there silently because the 'icu' structure retrieved
> this way was just called by dev_err(), only producing a
> '(NULL device *):' output on the console.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Otherwise:

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thanks!

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* [PATCH 04/17] irqchip/irq-mvebu-icu: fix wrong user data retrieval
@ 2018-04-30 13:49     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

In the title, I think "user data" is not really appropriate. "private
date" or "device private data" maybe ?

On Sat, 21 Apr 2018 15:55:24 +0200, Miquel Raynal wrote:
> The irq_domain structure has an host_data pointer that just stores user
> data. It is meant to not be touched by the IRQ core. However, when it
> comes to MSI, the MSI layer adds its own private data there with a
> structure that also has a host_data pointer.
> 
> Because this IRQ domain is an MSI domain, to access user data we should
> do a d->host_data->host_data, also wrapped as
> 'platform_msi_get_host_data()'.
> 
> This bug was lying there silently because the 'icu' structure retrieved
> this way was just called by dev_err(), only producing a
> '(NULL device *):' output on the console.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Otherwise:

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thanks!

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 05/17] irqchip/irq-mvebu-icu: clarify the reset operation of configured interrupts
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-30 13:51     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:51 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

On Sat, 21 Apr 2018 15:55:25 +0200, Miquel Raynal wrote:
> Rewrite a small section to clarify the reset operation of interrupts
> already configured by ATF that we want to handle in the driver. This
> will simplify the introduction of System Error Interrupts support.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Looks good to me.

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* [PATCH 05/17] irqchip/irq-mvebu-icu: clarify the reset operation of configured interrupts
@ 2018-04-30 13:51     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Sat, 21 Apr 2018 15:55:25 +0200, Miquel Raynal wrote:
> Rewrite a small section to clarify the reset operation of interrupts
> already configured by ATF that we want to handle in the driver. This
> will simplify the introduction of System Error Interrupts support.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Looks good to me.

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 06/17] irqchip/irq-mvebu-icu: switch to regmap
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-30 13:53     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:53 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

On Sat, 21 Apr 2018 15:55:26 +0200, Miquel Raynal wrote:
> The ICU DT nodes have now the 'syscon' compatible, we can switch to

have now -> now have

> regmap before splitting the code to support multiple platform devices to
> be probed (one for the ICU, one per interrupt group).
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

As I explained in the review of PATCH 03/17, I think we could simply
create the regmap in the ->probe() of the parent device, instead of
using the "syscon" property, which is mainly useful when there is no
parent device.

The rest of the conversion to regmap looks good otherwise.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* [PATCH 06/17] irqchip/irq-mvebu-icu: switch to regmap
@ 2018-04-30 13:53     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Sat, 21 Apr 2018 15:55:26 +0200, Miquel Raynal wrote:
> The ICU DT nodes have now the 'syscon' compatible, we can switch to

have now -> now have

> regmap before splitting the code to support multiple platform devices to
> be probed (one for the ICU, one per interrupt group).
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

As I explained in the review of PATCH 03/17, I think we could simply
create the regmap in the ->probe() of the parent device, instead of
using the "syscon" property, which is mainly useful when there is no
parent device.

The rest of the conversion to regmap looks good otherwise.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 06/17] irqchip/irq-mvebu-icu: switch to regmap
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-30 13:58     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:58 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

On Sat, 21 Apr 2018 15:55:26 +0200, Miquel Raynal wrote:

> +	icu->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, NULL);
> +	if (IS_ERR(icu->regmap))
> +		return PTR_ERR(icu->regmap);
> +
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	icu->base = devm_ioremap_resource(&pdev->dev, res);
> -	if (IS_ERR(icu->base)) {
> -		dev_err(&pdev->dev, "Failed to map icu base address.\n");
> -		return PTR_ERR(icu->base);
> -	}
> +	if (!res)
> +		return -ENODEV;

Another issue with relying on the "syscon" compatible string: your ICU
driver now *requires* that the DT has the "syscon" compatible string.
Otherwise, no regmap is created, and your
syscon_regmap_lookup_by_phandle() call will fail.

In fact, there is a very good hint that something is wrong in terms of
backward compatibility: your patch

  arm64: dts: marvell: add syscon compatible to CP110 ICU node

comes early in the series, separated from other DT changes. It should
come at the end of the series, with the rest of the DT changes. By
doing this, you could test your series with the driver changes, but not
the DT changes, and would have realized that the driver change in this
patch (PATCH 06/17) breaks DT backward compatibility.

This is IMO another good reason to not use the "syscon" property, but
simply have the driver initialize the regmap by itself. This will work
even with old DTs, as it will become just an internal implementation
detail of the driver.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* [PATCH 06/17] irqchip/irq-mvebu-icu: switch to regmap
@ 2018-04-30 13:58     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 13:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Sat, 21 Apr 2018 15:55:26 +0200, Miquel Raynal wrote:

> +	icu->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, NULL);
> +	if (IS_ERR(icu->regmap))
> +		return PTR_ERR(icu->regmap);
> +
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	icu->base = devm_ioremap_resource(&pdev->dev, res);
> -	if (IS_ERR(icu->base)) {
> -		dev_err(&pdev->dev, "Failed to map icu base address.\n");
> -		return PTR_ERR(icu->base);
> -	}
> +	if (!res)
> +		return -ENODEV;

Another issue with relying on the "syscon" compatible string: your ICU
driver now *requires* that the DT has the "syscon" compatible string.
Otherwise, no regmap is created, and your
syscon_regmap_lookup_by_phandle() call will fail.

In fact, there is a very good hint that something is wrong in terms of
backward compatibility: your patch

  arm64: dts: marvell: add syscon compatible to CP110 ICU node

comes early in the series, separated from other DT changes. It should
come at the end of the series, with the rest of the DT changes. By
doing this, you could test your series with the driver changes, but not
the DT changes, and would have realized that the driver change in this
patch (PATCH 06/17) breaks DT backward compatibility.

This is IMO another good reason to not use the "syscon" property, but
simply have the driver initialize the regmap by itself. This will work
even with old DTs, as it will become just an internal implementation
detail of the driver.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
  2018-04-28 10:48       ` Miquel Raynal
@ 2018-04-30 14:09         ` Rob Herring
  -1 siblings, 0 replies; 92+ messages in thread
From: Rob Herring @ 2018-04-30 14:09 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Thomas Petazzoni, Thomas Gleixner, Hanna Hawa,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Sebastian Hesselbarth

On Sat, Apr 28, 2018 at 5:48 AM, Miquel Raynal
<miquel.raynal@bootlin.com> wrote:
> Hi Rob,
>
> On Fri, 27 Apr 2018 15:50:32 -0500, Rob Herring <robh@kernel.org> wrote:
>
>> On Sat, Apr 21, 2018 at 03:55:34PM +0200, Miquel Raynal wrote:
>> > Describe the SEI (System Error Interrupt) controller driver. The
>> > controller is part of the GIC. It aggregates two types of interrupts,
>> > wired and MSIs from respectively the AP and the CPs, into a single SPI
>> > interrupt.
>> >
>> > Suggested-by: Haim Boot <hayim@marvell.com>
>> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
>> > ---
>> >  .../bindings/interrupt-controller/marvell,sei.txt  | 54 ++++++++++++++++++++++
>> >  1 file changed, 54 insertions(+)
>> >  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
>> >
>> > diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
>> > new file mode 100644
>> > index 000000000000..a246d59552b1
>> > --- /dev/null
>> > +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
>> > @@ -0,0 +1,54 @@
>> > +Marvell SEI (System Error Interrupt) Controller
>> > +-----------------------------------------------
>> > +
>> > +Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
>> > +It receives interrupts from several sources and aggregates them to a single
>> > +interrupt line (an SPI) on the primary interrupt controller.
>> > +
>> > +The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is
>> > +wired while a second set comes from the CPs by the mean of MSIs. Each
>> > +'domain' is represented as a subnode.
>> > +
>> > +Required properties:
>> > +
>> > +- compatible: should be "marvell,armada-8k-sei".
>> > +- reg: SEI registers location and length.
>> > +- interrupts: identifies the parent IRQ that will be triggered.
>> > +- #address-cells: should be '1', represents the position of the first
>> > +                  IRQ of a given type in the SEI range.
>> > +- #size-cells: should be '1', represents the number of a given type of
>> > +               IRQs.
>> > +
>> > +Child node 'sei-wired-controller' required properties:
>> > +
>> > +- reg: the range of wired interrupts.
>> > +- #interrupt-cells: number of cells to define an SEI wired interrupt
>> > +                    coming from the AP, should be 1. The cell is the IRQ
>> > +                    number.
>> > +- interrupt-controller: identifies the node as an interrupt controller.
>> > +
>> > +Child node 'sei-msi-controller' required properties:
>> > +
>> > +- reg: the range of non-wired interrupts triggered by way of MSIs.
>> > +- msi-controller: identifies the node as an MSI controller.
>> > +
>> > +Example:
>> > +
>> > +        sei: sei@3f0200 {
>> > +               compatible = "marvell,armada-8k-sei";
>> > +               reg = <0x3f0200 0x40>;
>> > +               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
>> > +               #address-cells = <1>;
>> > +               #size-cells = <1>;
>> > +
>> > +               sei_wired_controller: sei-wired-controller@0 {
>> > +                       reg = <0 21>;
>>
>> Using interrupt numbers in reg is strange.
>
> I thought the reg property was the one to choose here, I can of course
> change it, what would you suggest?
>
>>
>> > +                       #interrupt-cells = <1>;
>> > +                       interrupt-controller;
>> > +               };
>> > +
>> > +               sei_msi_controller: sei-msi-controller@21 {
>> > +                       reg = <21 43>;
>> > +                       msi-controller;
>>
>> Can't the parent be both an interrupt-controller and msi-controller?
>
> We need to know which one aggregates interrupts, which one receives
> MSIs and most importantly which interrupt is what (within the 64
> that are handled by the SEI).

You mean that 0-20 are wired and 21-63 are msi? "marvell,msi-base =
<21>;" in the parent would be sufficient for that though you may want
something more flexible to have multiple ranges.

It looks like there may already be similar bindings. See
'msi-available-ranges" and "{al,arm},msi-base-spi".

Rob

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

* [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
@ 2018-04-30 14:09         ` Rob Herring
  0 siblings, 0 replies; 92+ messages in thread
From: Rob Herring @ 2018-04-30 14:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Apr 28, 2018 at 5:48 AM, Miquel Raynal
<miquel.raynal@bootlin.com> wrote:
> Hi Rob,
>
> On Fri, 27 Apr 2018 15:50:32 -0500, Rob Herring <robh@kernel.org> wrote:
>
>> On Sat, Apr 21, 2018 at 03:55:34PM +0200, Miquel Raynal wrote:
>> > Describe the SEI (System Error Interrupt) controller driver. The
>> > controller is part of the GIC. It aggregates two types of interrupts,
>> > wired and MSIs from respectively the AP and the CPs, into a single SPI
>> > interrupt.
>> >
>> > Suggested-by: Haim Boot <hayim@marvell.com>
>> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
>> > ---
>> >  .../bindings/interrupt-controller/marvell,sei.txt  | 54 ++++++++++++++++++++++
>> >  1 file changed, 54 insertions(+)
>> >  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
>> >
>> > diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
>> > new file mode 100644
>> > index 000000000000..a246d59552b1
>> > --- /dev/null
>> > +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
>> > @@ -0,0 +1,54 @@
>> > +Marvell SEI (System Error Interrupt) Controller
>> > +-----------------------------------------------
>> > +
>> > +Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
>> > +It receives interrupts from several sources and aggregates them to a single
>> > +interrupt line (an SPI) on the primary interrupt controller.
>> > +
>> > +The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is
>> > +wired while a second set comes from the CPs by the mean of MSIs. Each
>> > +'domain' is represented as a subnode.
>> > +
>> > +Required properties:
>> > +
>> > +- compatible: should be "marvell,armada-8k-sei".
>> > +- reg: SEI registers location and length.
>> > +- interrupts: identifies the parent IRQ that will be triggered.
>> > +- #address-cells: should be '1', represents the position of the first
>> > +                  IRQ of a given type in the SEI range.
>> > +- #size-cells: should be '1', represents the number of a given type of
>> > +               IRQs.
>> > +
>> > +Child node 'sei-wired-controller' required properties:
>> > +
>> > +- reg: the range of wired interrupts.
>> > +- #interrupt-cells: number of cells to define an SEI wired interrupt
>> > +                    coming from the AP, should be 1. The cell is the IRQ
>> > +                    number.
>> > +- interrupt-controller: identifies the node as an interrupt controller.
>> > +
>> > +Child node 'sei-msi-controller' required properties:
>> > +
>> > +- reg: the range of non-wired interrupts triggered by way of MSIs.
>> > +- msi-controller: identifies the node as an MSI controller.
>> > +
>> > +Example:
>> > +
>> > +        sei: sei at 3f0200 {
>> > +               compatible = "marvell,armada-8k-sei";
>> > +               reg = <0x3f0200 0x40>;
>> > +               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
>> > +               #address-cells = <1>;
>> > +               #size-cells = <1>;
>> > +
>> > +               sei_wired_controller: sei-wired-controller at 0 {
>> > +                       reg = <0 21>;
>>
>> Using interrupt numbers in reg is strange.
>
> I thought the reg property was the one to choose here, I can of course
> change it, what would you suggest?
>
>>
>> > +                       #interrupt-cells = <1>;
>> > +                       interrupt-controller;
>> > +               };
>> > +
>> > +               sei_msi_controller: sei-msi-controller at 21 {
>> > +                       reg = <21 43>;
>> > +                       msi-controller;
>>
>> Can't the parent be both an interrupt-controller and msi-controller?
>
> We need to know which one aggregates interrupts, which one receives
> MSIs and most importantly which interrupt is what (within the 64
> that are handled by the SEI).

You mean that 0-20 are wired and 21-63 are msi? "marvell,msi-base =
<21>;" in the parent would be sufficient for that though you may want
something more flexible to have multiple ranges.

It looks like there may already be similar bindings. See
'msi-available-ranges" and "{al,arm},msi-base-spi".

Rob

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

* Re: [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-04-30 14:24     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 14:24 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello Miquèl,

Title should rather be: "add DT binding documentation for the Marvell
SEI controller" or something like that. Talking about "node" is a bit
weird here.

On Sat, 21 Apr 2018 15:55:34 +0200, Miquel Raynal wrote:
> Describe the SEI (System Error Interrupt) controller driver.

As soon as you say "driver" in a DT binding documentation, you're on
the wrong track. A binding documentation never describes a driver, but
a piece of hardware.

> The controller is part of the GIC.

I don't think we should state that, especially since it's not part of
the GIC shipped by ARM as far as I know, and we represent it as a
separate Device Tree nodes.

> diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> new file mode 100644
> index 000000000000..a246d59552b1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> @@ -0,0 +1,54 @@
> +Marvell SEI (System Error Interrupt) Controller
> +-----------------------------------------------
> +
> +Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
> +It receives interrupts from several sources and aggregates them to a single
> +interrupt line (an SPI) on the primary interrupt controller.

Rather than primary, I would use "parent" here.

> +The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is

"IRQ chip" is a Linux concept, I would stick to "This interrupt
controller can handle up ..."

> +wired while a second set comes from the CPs by the mean of MSIs. Each
> +'domain' is represented as a subnode.
> +
> +Required properties:
> +
> +- compatible: should be "marvell,armada-8k-sei".
> +- reg: SEI registers location and length.
> +- interrupts: identifies the parent IRQ that will be triggered.
> +- #address-cells: should be '1', represents the position of the first
> +                  IRQ of a given type in the SEI range.
> +- #size-cells: should be '1', represents the number of a given type of
> +               IRQs.

What is the "given type" ?

> +Child node 'sei-wired-controller' required properties:
> +
> +- reg: the range of wired interrupts.
> +- #interrupt-cells: number of cells to define an SEI wired interrupt
> +                    coming from the AP, should be 1. The cell is the IRQ
> +                    number.
> +- interrupt-controller: identifies the node as an interrupt controller.
> +
> +Child node 'sei-msi-controller' required properties:
> +
> +- reg: the range of non-wired interrupts triggered by way of MSIs.
> +- msi-controller: identifies the node as an MSI controller.
> +
> +Example:
> +
> +        sei: sei@3f0200 {
> +               compatible = "marvell,armada-8k-sei";
> +               reg = <0x3f0200 0x40>;
> +               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +
> +               sei_wired_controller: sei-wired-controller@0 {
> +                       reg = <0 21>;
> +                       #interrupt-cells = <1>;
> +                       interrupt-controller;
> +               };
> +
> +               sei_msi_controller: sei-msi-controller@21 {
> +                       reg = <21 43>;
> +                       msi-controller;
> +               };

As Rob asked, I'm not sure we need subnodes here. Did you check if it
is was doable to have a single node which is both an
interrupt-controller and a msi-controller ?

And indeed, as Rob said, using reg to encode interrupt ranges doesn't
look good.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
@ 2018-04-30 14:24     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-04-30 14:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Miqu?l,

Title should rather be: "add DT binding documentation for the Marvell
SEI controller" or something like that. Talking about "node" is a bit
weird here.

On Sat, 21 Apr 2018 15:55:34 +0200, Miquel Raynal wrote:
> Describe the SEI (System Error Interrupt) controller driver.

As soon as you say "driver" in a DT binding documentation, you're on
the wrong track. A binding documentation never describes a driver, but
a piece of hardware.

> The controller is part of the GIC.

I don't think we should state that, especially since it's not part of
the GIC shipped by ARM as far as I know, and we represent it as a
separate Device Tree nodes.

> diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> new file mode 100644
> index 000000000000..a246d59552b1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> @@ -0,0 +1,54 @@
> +Marvell SEI (System Error Interrupt) Controller
> +-----------------------------------------------
> +
> +Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
> +It receives interrupts from several sources and aggregates them to a single
> +interrupt line (an SPI) on the primary interrupt controller.

Rather than primary, I would use "parent" here.

> +The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is

"IRQ chip" is a Linux concept, I would stick to "This interrupt
controller can handle up ..."

> +wired while a second set comes from the CPs by the mean of MSIs. Each
> +'domain' is represented as a subnode.
> +
> +Required properties:
> +
> +- compatible: should be "marvell,armada-8k-sei".
> +- reg: SEI registers location and length.
> +- interrupts: identifies the parent IRQ that will be triggered.
> +- #address-cells: should be '1', represents the position of the first
> +                  IRQ of a given type in the SEI range.
> +- #size-cells: should be '1', represents the number of a given type of
> +               IRQs.

What is the "given type" ?

> +Child node 'sei-wired-controller' required properties:
> +
> +- reg: the range of wired interrupts.
> +- #interrupt-cells: number of cells to define an SEI wired interrupt
> +                    coming from the AP, should be 1. The cell is the IRQ
> +                    number.
> +- interrupt-controller: identifies the node as an interrupt controller.
> +
> +Child node 'sei-msi-controller' required properties:
> +
> +- reg: the range of non-wired interrupts triggered by way of MSIs.
> +- msi-controller: identifies the node as an MSI controller.
> +
> +Example:
> +
> +        sei: sei at 3f0200 {
> +               compatible = "marvell,armada-8k-sei";
> +               reg = <0x3f0200 0x40>;
> +               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +
> +               sei_wired_controller: sei-wired-controller at 0 {
> +                       reg = <0 21>;
> +                       #interrupt-cells = <1>;
> +                       interrupt-controller;
> +               };
> +
> +               sei_msi_controller: sei-msi-controller at 21 {
> +                       reg = <21 43>;
> +                       msi-controller;
> +               };

As Rob asked, I'm not sure we need subnodes here. Did you check if it
is was doable to have a single node which is both an
interrupt-controller and a msi-controller ?

And indeed, as Rob said, using reg to encode interrupt ranges doesn't
look good.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 07/17] irqchip/irq-mvebu-icu: make irq_domain local
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-05-02  8:02     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-05-02  8:02 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

On Sat, 21 Apr 2018 15:55:27 +0200, Miquel Raynal wrote:
> Make the current MSI irq_domain local to ease the split between ICU
> platform device code and NSR platform device code.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* [PATCH 07/17] irqchip/irq-mvebu-icu: make irq_domain local
@ 2018-05-02  8:02     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-05-02  8:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Sat, 21 Apr 2018 15:55:27 +0200, Miquel Raynal wrote:
> Make the current MSI irq_domain local to ease the split between ICU
> platform device code and NSR platform device code.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 08/17] irqchip/irq-mvebu-icu: disociate ICU and NSR
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-05-02  8:03     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-05-02  8:03 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

On Sat, 21 Apr 2018 15:55:28 +0200, Miquel Raynal wrote:
> NSR (non-secure interrupts) are handled in the ICU driver like if there
> was only this type of interrupt in the ICU. Change this behavior to
> prepare the introduction of SEI (System Error Interrupts) support by
> moving the NSR code in a separate function. This is done under the form
> of a 'probe' function to ease future migration to NSR/SEI being platform
> devices part of the ICU.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thanks!

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* [PATCH 08/17] irqchip/irq-mvebu-icu: disociate ICU and NSR
@ 2018-05-02  8:03     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-05-02  8:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Sat, 21 Apr 2018 15:55:28 +0200, Miquel Raynal wrote:
> NSR (non-secure interrupts) are handled in the ICU driver like if there
> was only this type of interrupt in the ICU. Change this behavior to
> prepare the introduction of SEI (System Error Interrupts) support by
> moving the NSR code in a separate function. This is done under the form
> of a 'probe' function to ease future migration to NSR/SEI being platform
> devices part of the ICU.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thanks!

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 09/17] irqchip/irq-mvebu-icu: support ICU subnodes
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-05-02  8:13     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-05-02  8:13 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello Miquèl,

On Sat, 21 Apr 2018 15:55:29 +0200, Miquel Raynal wrote:
> Introduce new bindings for the ICU.

Perhaps this should explain *why* we need new bindings.

> Each DT subnode of the ICU represents a type of interrupt that should
> be handled separately. Add the possibility for the ICU to have subnodes
> and probe each of them automatically with devm_platform_populate(). If
> the node as no child, the probe function for NSRs will still be called
> 'manually'.

 ... in order to preserve backward compatibility with Device Trees
 using the old binding.

> +static struct mvebu_icu *mvebu_dev_get_drvdata(struct platform_device *pdev)

The function should be prefixed by mvebu_icu_, not just mvebu_.

> +{
> +	struct mvebu_icu *icu;
> +
> +	icu = dev_get_drvdata(&pdev->dev);
> +	if (icu) {
> +		/* Legacy bindings: get the device data */

I find this comment weird, because it doesn't document what the test
just below is doing.

> +		if (!icu->legacy_bindings)
> +			return ERR_PTR(-EINVAL);
> +	} else {
> +		/* New bindings: get the parent device (ICU) data */
> +		icu = dev_get_drvdata(pdev->dev.parent);
> +		if (!icu)
> +			return ERR_PTR(-ENODEV);
> +		if (icu->legacy_bindings)
> +			return ERR_PTR(-EINVAL);
> +	}


> @@ -144,7 +170,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
>  		goto free_irqd;
>  	}
>  
> -	icu_irqd->icu_group = fwspec->param[0];
> +	if (icu->legacy_bindings)
> +		icu_irqd->icu_group = fwspec->param[0];
> +	else
> +		icu_irqd->icu_group = ICU_GRP_NSR;

In practice here fwspec->param[0] is always going to be equal to
ICU_GRP_NSR, but OK, the test makes sense as in a future commit, the
"else" case will be changed to support SEIs.

> +static const struct of_device_id mvebu_icu_nsr_of_match[] = {
> +	{ .compatible = "marvell,cp110-icu-nsr", },
> +	{},
> +};
> +
> +static struct platform_driver mvebu_icu_nsr_driver = {
> +	.probe  = mvebu_icu_nsr_probe,
> +	.driver = {
> +		.name = "mvebu-icu-nsr",
> +		.of_match_table = mvebu_icu_nsr_of_match,
> +	},
> +};
> +builtin_platform_driver(mvebu_icu_nsr_driver);

I'm not sure why you call this icu_nsr here, and change it later to
icu_subset. Wouldn't it make sense to call it right away with the final
name ? Note that this is not a very strong request to change this
aspect, I'm fine with how it's done today, it's just that I would have
done it differently.

Other than that, looks good to me.

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 09/17] irqchip/irq-mvebu-icu: support ICU subnodes
@ 2018-05-02  8:13     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-05-02  8:13 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Miqu?l,

On Sat, 21 Apr 2018 15:55:29 +0200, Miquel Raynal wrote:
> Introduce new bindings for the ICU.

Perhaps this should explain *why* we need new bindings.

> Each DT subnode of the ICU represents a type of interrupt that should
> be handled separately. Add the possibility for the ICU to have subnodes
> and probe each of them automatically with devm_platform_populate(). If
> the node as no child, the probe function for NSRs will still be called
> 'manually'.

 ... in order to preserve backward compatibility with Device Trees
 using the old binding.

> +static struct mvebu_icu *mvebu_dev_get_drvdata(struct platform_device *pdev)

The function should be prefixed by mvebu_icu_, not just mvebu_.

> +{
> +	struct mvebu_icu *icu;
> +
> +	icu = dev_get_drvdata(&pdev->dev);
> +	if (icu) {
> +		/* Legacy bindings: get the device data */

I find this comment weird, because it doesn't document what the test
just below is doing.

> +		if (!icu->legacy_bindings)
> +			return ERR_PTR(-EINVAL);
> +	} else {
> +		/* New bindings: get the parent device (ICU) data */
> +		icu = dev_get_drvdata(pdev->dev.parent);
> +		if (!icu)
> +			return ERR_PTR(-ENODEV);
> +		if (icu->legacy_bindings)
> +			return ERR_PTR(-EINVAL);
> +	}


> @@ -144,7 +170,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
>  		goto free_irqd;
>  	}
>  
> -	icu_irqd->icu_group = fwspec->param[0];
> +	if (icu->legacy_bindings)
> +		icu_irqd->icu_group = fwspec->param[0];
> +	else
> +		icu_irqd->icu_group = ICU_GRP_NSR;

In practice here fwspec->param[0] is always going to be equal to
ICU_GRP_NSR, but OK, the test makes sense as in a future commit, the
"else" case will be changed to support SEIs.

> +static const struct of_device_id mvebu_icu_nsr_of_match[] = {
> +	{ .compatible = "marvell,cp110-icu-nsr", },
> +	{},
> +};
> +
> +static struct platform_driver mvebu_icu_nsr_driver = {
> +	.probe  = mvebu_icu_nsr_probe,
> +	.driver = {
> +		.name = "mvebu-icu-nsr",
> +		.of_match_table = mvebu_icu_nsr_of_match,
> +	},
> +};
> +builtin_platform_driver(mvebu_icu_nsr_driver);

I'm not sure why you call this icu_nsr here, and change it later to
icu_subset. Wouldn't it make sense to call it right away with the final
name ? Note that this is not a very strong request to change this
aspect, I'm fine with how it's done today, it's just that I would have
done it differently.

Other than that, looks good to me.

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 10/17] irqchip/irq-mvebu-sei: add new driver for Marvell SEI
  2018-04-21 13:55   ` Miquel Raynal
@ 2018-05-02  9:17     ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-05-02  9:17 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

On Sat, 21 Apr 2018 15:55:30 +0200, Miquel Raynal wrote:

> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 5ed465ab1c76..6b5b75cb4694 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -73,6 +73,7 @@ obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
>  obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
>  obj-$(CONFIG_MSCC_OCELOT_IRQ)		+= irq-mscc-ocelot.o
>  obj-$(CONFIG_MVEBU_GICP)		+= irq-mvebu-gicp.o
> +obj-$(CONFIG_MVEBU_SEI)			+= irq-mvebu-sei.o
>  obj-$(CONFIG_MVEBU_ICU)			+= irq-mvebu-icu.o
>  obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
>  obj-$(CONFIG_MVEBU_PIC)			+= irq-mvebu-pic.o

Alphabetic ordering would put SEI after PIC I guess :)

> diff --git a/drivers/irqchip/irq-mvebu-sei.c b/drivers/irqchip/irq-mvebu-sei.c
> new file mode 100644
> index 000000000000..5c12c74e3f09
> --- /dev/null
> +++ b/drivers/irqchip/irq-mvebu-sei.c
> @@ -0,0 +1,449 @@
> +// SPDX-License-Identifier: GPL-2.0 OR X11

License for code is GPL-2.0 only. We use GPL-2.0 OR X11 for Device
Trees.

> +#define pr_fmt(fmt) "mvebu-sei: " fmt
> +
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/kernel.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/msi.h>
> +#include <linux/platform_device.h>
> +#include <linux/irqchip.h>
> +
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +#define GICP_SET_SEI_OFFSET	0x30
> +#define GICP_CLR_SEI_OFFSET	GICP_SET_SEI_OFFSET

Why do you have this concept of set/clr if there is only one register ?
I assume that if there is only a "set" register, it means that SEI
interrupts can only be edge triggered, contrary to NSR interrupts,
which have separate set/clr to support level-triggered interrupts.

Having only a "set" offset means that we can rely on the existing
"struct msi_msg" to convey both the MSI doorbell address and payload,
and we don't need the mvebu_gicp_get_doorbells() hack.

> +/* Cause register */
> +#define GICP_SECR(idx)		(0x0  + (idx * 0x4))
> +/* Mask register */
> +#define GICP_SEMR(idx)		(0x20 + (idx * 0x4))

Minor nit: order register definitions by order of increasing offset,
i.e the GICP_SET_SEI_OFFSET should be defined here.

> +#define SEI_IRQ_NB_PER_REG	32
> +#define SEI_IRQ_REG_NB		2

s/NB/COUNT/

> +#define SEI_IRQ_NB		(SEI_IRQ_NB_PER_REG * SEI_IRQ_REG_NB)

Ditto.

> +#define SEI_IRQ_REG_IDX(irq_id)	(irq_id / SEI_IRQ_NB_PER_REG)
> +#define SEI_IRQ_REG_BIT(irq_id)	(irq_id % SEI_IRQ_NB_PER_REG)
> +
> +struct mvebu_sei_interrupt_range {
> +	u32 first;
> +	u32 number;
> +};
> +
> +struct mvebu_sei {
> +	struct device *dev;
> +	void __iomem *base;
> +	struct resource *res;
> +	struct irq_domain *ap_domain;
> +	struct irq_domain *cp_domain;
> +	struct mvebu_sei_interrupt_range ap_interrupts;
> +	struct mvebu_sei_interrupt_range cp_interrupts;
> +	/* Lock on MSI allocations/releases */
> +	spinlock_t cp_msi_lock;
> +	DECLARE_BITMAP(cp_msi_bitmap, SEI_IRQ_NB);
> +};
> +
> +static int mvebu_sei_domain_to_sei_irq(struct mvebu_sei *sei,
> +				       struct irq_domain *domain,
> +				       irq_hw_number_t hwirq)
> +{
> +	if (domain == sei->ap_domain)
> +		return sei->ap_interrupts.first + hwirq;
> +	else
> +		return sei->cp_interrupts.first + hwirq;

I am not entirely clear whether we need subnodes or not in this
binding, but I guess we do because we have one subset of the interrupts
that are wired interrupts, and another part that are MSI triggered.

Perhaps this is one aspect on which Marc Zyngier can comment ?

> +static void mvebu_sei_reset(struct mvebu_sei *sei)
> +{
> +	u32 reg_idx;
> +
> +	for (reg_idx = 0; reg_idx < SEI_IRQ_REG_NB; reg_idx++) {
> +		/* Clear all cause bits */
> +		writel(0xFFFFFFFF, sei->base + GICP_SECR(reg_idx));
> +		/* Enable all interrupts */
> +		writel(0, sei->base + GICP_SEMR(reg_idx));

Enabling interrupts by default ? This looks weird. They should only be
enabled... when enabled.

> +int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
> +			    phys_addr_t *clr)
> +{
> +	struct platform_device *pdev;
> +	struct mvebu_sei *sei;
> +
> +	pdev = of_find_device_by_node(dn->parent);
> +	if (!pdev)
> +		return -ENODEV;
> +
> +	sei = platform_get_drvdata(pdev);
> +	if (!sei)
> +		return -ENODEV;
> +
> +	*set = (phys_addr_t)(sei->res->start + GICP_SET_SEI_OFFSET);
> +	*clr = (phys_addr_t)(sei->res->start + GICP_CLR_SEI_OFFSET);
> +
> +	return 0;
> +}

As I said above, I believe this hack is not needed, because SEIs are
edge-triggered, and we have a single SET_SEI_OFFSET MSI doorbell
address to convey, which makes "struct msi_msg" as it is today
sufficient.

> +static void mvebu_sei_mask_irq(struct irq_data *d)
> +{
> +	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
> +	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);

This doesn't look right. The d->hwirq is relative to the beginning of
the domain, while you should use sei_irq here. For example, the SEI
n°32 (first interrupt in the second register) will have d->hwirq = 11,
because it is the 11th SEI interrupt for the CP. So here, you will
conclude that reg_idx = 0, while it should be reg_idx = 1.

> +	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
> +	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
> +	u32 reg;
> +
> +	/* 1 disables the interrupt */
> +	reg =  readl(sei->base + GICP_SEMR(reg_idx));
> +	writel(reg | irq_mask, sei->base + GICP_SEMR(reg_idx));

Personal taste here, but I prefer:

	reg =  readl(sei->base + GICP_SEMR(reg_idx));
	reg |= BIT(SEI_IRQ_REG_BIT(sei_irq));
	writel(reg, sei->base + GICP_SEMR(reg_idx));

> +static void mvebu_sei_unmask_irq(struct irq_data *d)
> +{
> +	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
> +	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);

Same mistake as above I believe.

> +	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
> +	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
> +	u32 reg;
> +
> +	/* 0 enables the interrupt */
> +	reg = readl(sei->base + GICP_SEMR(reg_idx));
> +	writel(reg & ~irq_mask, sei->base + GICP_SEMR(reg_idx));

And same nitpick comment :-)

> +static int mvebu_sei_irq_domain_alloc(struct irq_domain *domain,
> +				      unsigned int virq, unsigned int nr_irqs,
> +				      void *args)

I think the coding style says that arguments should be aligned, no ?

> +{
> +	struct mvebu_sei *sei = domain->host_data;
> +	struct irq_fwspec *fwspec = args;
> +	struct irq_chip *irq_chip;
> +	int sei_hwirq, hwirq;
> +	int ret;
> +
> +	/* Software only supports single allocations for now */
> +	if (nr_irqs != 1)
> +		return -ENOTSUPP;
> +
> +	if (domain == sei->ap_domain) {
> +		irq_chip = &mvebu_sei_ap_wired_irq_chip;
> +		hwirq = fwspec->param[0];
> +	} else {
> +		irq_chip = &mvebu_sei_cp_msi_irq_chip;
> +		spin_lock(&sei->cp_msi_lock);
> +		hwirq = bitmap_find_free_region(sei->cp_msi_bitmap, SEI_IRQ_NB,
> +						0);
> +		spin_unlock(&sei->cp_msi_lock);
> +		if (hwirq < 0)
> +			return -ENOSPC;
> +	}
> +
> +	sei_hwirq = mvebu_sei_domain_to_sei_irq(sei, domain, hwirq);
> +
> +	fwspec->fwnode = domain->parent->fwnode;
> +	fwspec->param_count = 3;
> +	fwspec->param[0] = GIC_SPI;
> +	fwspec->param[1] = sei_hwirq;
> +	fwspec->param[2] = IRQ_TYPE_EDGE_RISING;

Maybe it's me being confused, but I thought all SEI interrupts were
muxed together to a single SPI for the parent GIC. But here, you
allocate different SPIs at the GIC level. Intuitively, this doesn't
look good. Haven't you copy/pasted too much from the gicp driver, where
we have a 1:1 mapping between interrupts coming into the GICP and
interrupts signaled by the GICP to the GIC, while here we have a N:1
mapping, with N interrupts coming into the GICP_SEI, and only one
interrupt leaving the GICP_SEI to the GIC ?

> +static const struct irq_domain_ops mvebu_sei_ap_domain_ops = {
> +	.xlate = irq_domain_xlate_onecell,
> +	.alloc = mvebu_sei_irq_domain_alloc,
> +	.free = mvebu_sei_irq_domain_free,
> +};
> +
> +static const struct irq_domain_ops mvebu_sei_cp_domain_ops = {
> +	.xlate = irq_domain_xlate_twocell,
> +	.alloc = mvebu_sei_irq_domain_alloc,
> +	.free = mvebu_sei_irq_domain_free,
> +};

Why do you need two cells for the interrupts coming from the CP and
only one cell for the interrupts coming from the AP ?

For thermal in the AP, you do:

+					interrupt-parent = <&sei_wired_controller>;
+					interrupts = <18>;

i.e, you don't specify an interrupt type. For thermal in the CP, you do:

+				interrupts-extended =
+					<&CP110_LABEL(icu_sei) 116 IRQ_TYPE_LEVEL_HIGH>;

here you specify an interrupt type. I'm not sure why you have this
difference. Even more so because I think a SEI level interrupt is not
possible, since you only have a "SET" register and no "CLR" register.

Some guidance from Marc here might be useful perhaps.


> +static int mvebu_sei_probe(struct platform_device *pdev)
> +{
> +	struct device_node *node = pdev->dev.of_node, *parent, *child;
> +	struct irq_domain *parent_domain, *plat_domain;
> +	struct mvebu_sei *sei;
> +	const __be32 *property;
> +	u32 top_level_spi, size;
> +	int ret;
> +
> +	sei = devm_kzalloc(&pdev->dev, sizeof(*sei), GFP_KERNEL);
> +	if (!sei)
> +		return -ENOMEM;
> +
> +	sei->dev = &pdev->dev;
> +
> +	spin_lock_init(&sei->cp_msi_lock);
> +
> +	sei->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!sei->res) {
> +		dev_err(sei->dev, "Failed to retrieve SEI resource\n");
> +		return -ENODEV;
> +	}
> +
> +	sei->base = devm_ioremap(sei->dev, sei->res->start,
> +				 resource_size(sei->res));
> +	if (!sei->base) {
> +		dev_err(sei->dev, "Failed to remap SEI resource\n");
> +		return -ENODEV;
> +	}

Use devm_ioremap_resource() here, and remove the error handling of
platform_get_resource(), because it's already taken care of by
devm_ioremap_resource().

> +	/*
> +	 * Reserve the single (top-level) parent SPI IRQ from which all the
> +	 * interrupts handled by this driver will be signaled.
> +	 */
> +	top_level_spi = irq_of_parse_and_map(node, 0);
> +	if (top_level_spi <= 0) {
> +		dev_err(sei->dev, "Failed to retrieve top-level SPI IRQ\n");
> +		return -ENODEV;
> +	}

Rather than top_level_spi, something like parent_irq would make more
sense to me.

> +	irq_set_chained_handler(top_level_spi, mvebu_sei_handle_cascade_irq);
> +	irq_set_handler_data(top_level_spi, sei);
> +
> +	/*
> +	 * SEIs in the range [ 0; 20] are wired and come from the AP.
> +	 * SEIs in the range [21; 63] are CP SEI and are triggered through MSIs.
> +	 *
> +	 * Each SEI 'domain' is represented as a subnode.
> +	 */
> +
> +	/* Get a reference to the parent domain to create a hierarchy */
> +	parent = of_irq_find_parent(node);
> +	if (!parent) {
> +		dev_err(sei->dev, "Failed to find parent IRQ node\n");
> +		ret = -ENODEV;
> +		goto dispose_irq;
> +	}
> +
> +	parent_domain = irq_find_host(parent);
> +	if (!parent_domain) {
> +		dev_err(sei->dev, "Failed to find parent IRQ domain\n");
> +		ret = -ENODEV;
> +		goto dispose_irq;
> +	}
> +
> +	/* Create the 'wired' hierarchy */
> +	child = of_find_node_by_name(node, "sei-wired-controller");
> +	if (!child) {
> +		dev_err(sei->dev, "Missing 'sei-wired-controller' subnode\n");
> +		ret = -ENODEV;
> +		goto dispose_irq;
> +	}

Don't forget to of_node_put(child) once you're done using this DT node
reference.

> +
> +	property = of_get_property(child, "reg", &size);
> +	if (!property || size != (2 * sizeof(u32))) {
> +		dev_err(sei->dev, "Missing subnode 'reg' property\n");
> +		ret = -ENODEV;
> +		goto dispose_irq;
> +	}

As Rob said, I don't think the "reg" property is appropriate for this
usage.

> +	sei->ap_interrupts.first = be32_to_cpu(property[0]);
> +	sei->ap_interrupts.number = be32_to_cpu(property[1]);
> +	sei->ap_domain = irq_domain_create_hierarchy(parent_domain, 0,
> +						     sei->ap_interrupts.number,
> +						     of_node_to_fwnode(child),
> +						     &mvebu_sei_ap_domain_ops,
> +						     sei);
> +	if (!sei->ap_domain) {
> +		dev_err(sei->dev, "Failed to create AP IRQ domain\n");
> +		ret = -ENOMEM;
> +		goto dispose_irq;
> +	}
> +
> +	/* Create the 'MSI' hierarchy */
> +	child = of_find_node_by_name(node, "sei-msi-controller");
> +	if (!child) {
> +		dev_err(sei->dev, "Missing 'sei-msi-controller' subnode\n");
> +		ret = -ENODEV;
> +		goto remove_ap_domain;
> +	}

Ditto: missing of_node_put(child) somewhere below to balance
of_find_node_by_name().

> +	property = of_get_property(child, "reg", &size);
> +	if (!property || size != (2 * sizeof(u32))) {
> +		dev_err(sei->dev, "Missing subnode 'reg' property\n");
> +		ret = -ENODEV;
> +		goto remove_ap_domain;
> +	}
> +
> +	sei->cp_interrupts.first = be32_to_cpu(property[0]);
> +	sei->cp_interrupts.number = be32_to_cpu(property[1]);
> +	sei->cp_domain = irq_domain_create_hierarchy(parent_domain, 0,
> +						     sei->cp_interrupts.number,
> +						     of_node_to_fwnode(child),
> +						     &mvebu_sei_cp_domain_ops,
> +						     sei);
> +	if (!sei->cp_domain) {
> +		pr_err("Failed to create CPs IRQ domain\n");
> +		ret = -ENOMEM;
> +		goto remove_ap_domain;
> +	}
> +
> +	plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(child),
> +						     &mvebu_sei_msi_domain_info,
> +						     sei->cp_domain);
> +	if (!plat_domain) {
> +		pr_err("Failed to create CPs MSI domain\n");
> +		ret = -ENOMEM;
> +		goto remove_cp_domain;
> +	}



> +
> +	platform_set_drvdata(pdev, sei);
> +
> +	mvebu_sei_reset(sei);

Please do the reset *before* registering the IRQ domains, it's more
logical to have the HW ready and then expose it to Linux rather than
the opposite.

It would be nice to have the review from Marc on this driver,
especially on whether the SEI is properly modeled in terms of IRQ
domains;

> diff --git a/drivers/irqchip/irq-mvebu-sei.h b/drivers/irqchip/irq-mvebu-sei.h
> new file mode 100644
> index 000000000000..f0c12a441923
> --- /dev/null
> +++ b/drivers/irqchip/irq-mvebu-sei.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __MVEBU_SEI_H__
> +#define __MVEBU_SEI_H__
> +
> +#include <linux/types.h>
> +
> +struct device_node;
> +
> +int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
> +			    phys_addr_t *clr);
> +
> +#endif /* __MVEBU_SEI_H__ */

This header file can be removed if you drop mvebu_sei_get_doorbells(),
as suggested above.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 10/17] irqchip/irq-mvebu-sei: add new driver for Marvell SEI
@ 2018-05-02  9:17     ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-05-02  9:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Sat, 21 Apr 2018 15:55:30 +0200, Miquel Raynal wrote:

> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 5ed465ab1c76..6b5b75cb4694 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -73,6 +73,7 @@ obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
>  obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
>  obj-$(CONFIG_MSCC_OCELOT_IRQ)		+= irq-mscc-ocelot.o
>  obj-$(CONFIG_MVEBU_GICP)		+= irq-mvebu-gicp.o
> +obj-$(CONFIG_MVEBU_SEI)			+= irq-mvebu-sei.o
>  obj-$(CONFIG_MVEBU_ICU)			+= irq-mvebu-icu.o
>  obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
>  obj-$(CONFIG_MVEBU_PIC)			+= irq-mvebu-pic.o

Alphabetic ordering would put SEI after PIC I guess :)

> diff --git a/drivers/irqchip/irq-mvebu-sei.c b/drivers/irqchip/irq-mvebu-sei.c
> new file mode 100644
> index 000000000000..5c12c74e3f09
> --- /dev/null
> +++ b/drivers/irqchip/irq-mvebu-sei.c
> @@ -0,0 +1,449 @@
> +// SPDX-License-Identifier: GPL-2.0 OR X11

License for code is GPL-2.0 only. We use GPL-2.0 OR X11 for Device
Trees.

> +#define pr_fmt(fmt) "mvebu-sei: " fmt
> +
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/kernel.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/msi.h>
> +#include <linux/platform_device.h>
> +#include <linux/irqchip.h>
> +
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +#define GICP_SET_SEI_OFFSET	0x30
> +#define GICP_CLR_SEI_OFFSET	GICP_SET_SEI_OFFSET

Why do you have this concept of set/clr if there is only one register ?
I assume that if there is only a "set" register, it means that SEI
interrupts can only be edge triggered, contrary to NSR interrupts,
which have separate set/clr to support level-triggered interrupts.

Having only a "set" offset means that we can rely on the existing
"struct msi_msg" to convey both the MSI doorbell address and payload,
and we don't need the mvebu_gicp_get_doorbells() hack.

> +/* Cause register */
> +#define GICP_SECR(idx)		(0x0  + (idx * 0x4))
> +/* Mask register */
> +#define GICP_SEMR(idx)		(0x20 + (idx * 0x4))

Minor nit: order register definitions by order of increasing offset,
i.e the GICP_SET_SEI_OFFSET should be defined here.

> +#define SEI_IRQ_NB_PER_REG	32
> +#define SEI_IRQ_REG_NB		2

s/NB/COUNT/

> +#define SEI_IRQ_NB		(SEI_IRQ_NB_PER_REG * SEI_IRQ_REG_NB)

Ditto.

> +#define SEI_IRQ_REG_IDX(irq_id)	(irq_id / SEI_IRQ_NB_PER_REG)
> +#define SEI_IRQ_REG_BIT(irq_id)	(irq_id % SEI_IRQ_NB_PER_REG)
> +
> +struct mvebu_sei_interrupt_range {
> +	u32 first;
> +	u32 number;
> +};
> +
> +struct mvebu_sei {
> +	struct device *dev;
> +	void __iomem *base;
> +	struct resource *res;
> +	struct irq_domain *ap_domain;
> +	struct irq_domain *cp_domain;
> +	struct mvebu_sei_interrupt_range ap_interrupts;
> +	struct mvebu_sei_interrupt_range cp_interrupts;
> +	/* Lock on MSI allocations/releases */
> +	spinlock_t cp_msi_lock;
> +	DECLARE_BITMAP(cp_msi_bitmap, SEI_IRQ_NB);
> +};
> +
> +static int mvebu_sei_domain_to_sei_irq(struct mvebu_sei *sei,
> +				       struct irq_domain *domain,
> +				       irq_hw_number_t hwirq)
> +{
> +	if (domain == sei->ap_domain)
> +		return sei->ap_interrupts.first + hwirq;
> +	else
> +		return sei->cp_interrupts.first + hwirq;

I am not entirely clear whether we need subnodes or not in this
binding, but I guess we do because we have one subset of the interrupts
that are wired interrupts, and another part that are MSI triggered.

Perhaps this is one aspect on which Marc Zyngier can comment ?

> +static void mvebu_sei_reset(struct mvebu_sei *sei)
> +{
> +	u32 reg_idx;
> +
> +	for (reg_idx = 0; reg_idx < SEI_IRQ_REG_NB; reg_idx++) {
> +		/* Clear all cause bits */
> +		writel(0xFFFFFFFF, sei->base + GICP_SECR(reg_idx));
> +		/* Enable all interrupts */
> +		writel(0, sei->base + GICP_SEMR(reg_idx));

Enabling interrupts by default ? This looks weird. They should only be
enabled... when enabled.

> +int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
> +			    phys_addr_t *clr)
> +{
> +	struct platform_device *pdev;
> +	struct mvebu_sei *sei;
> +
> +	pdev = of_find_device_by_node(dn->parent);
> +	if (!pdev)
> +		return -ENODEV;
> +
> +	sei = platform_get_drvdata(pdev);
> +	if (!sei)
> +		return -ENODEV;
> +
> +	*set = (phys_addr_t)(sei->res->start + GICP_SET_SEI_OFFSET);
> +	*clr = (phys_addr_t)(sei->res->start + GICP_CLR_SEI_OFFSET);
> +
> +	return 0;
> +}

As I said above, I believe this hack is not needed, because SEIs are
edge-triggered, and we have a single SET_SEI_OFFSET MSI doorbell
address to convey, which makes "struct msi_msg" as it is today
sufficient.

> +static void mvebu_sei_mask_irq(struct irq_data *d)
> +{
> +	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
> +	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);

This doesn't look right. The d->hwirq is relative to the beginning of
the domain, while you should use sei_irq here. For example, the SEI
n?32 (first interrupt in the second register) will have d->hwirq = 11,
because it is the 11th SEI interrupt for the CP. So here, you will
conclude that reg_idx = 0, while it should be reg_idx = 1.

> +	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
> +	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
> +	u32 reg;
> +
> +	/* 1 disables the interrupt */
> +	reg =  readl(sei->base + GICP_SEMR(reg_idx));
> +	writel(reg | irq_mask, sei->base + GICP_SEMR(reg_idx));

Personal taste here, but I prefer:

	reg =  readl(sei->base + GICP_SEMR(reg_idx));
	reg |= BIT(SEI_IRQ_REG_BIT(sei_irq));
	writel(reg, sei->base + GICP_SEMR(reg_idx));

> +static void mvebu_sei_unmask_irq(struct irq_data *d)
> +{
> +	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
> +	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);

Same mistake as above I believe.

> +	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
> +	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
> +	u32 reg;
> +
> +	/* 0 enables the interrupt */
> +	reg = readl(sei->base + GICP_SEMR(reg_idx));
> +	writel(reg & ~irq_mask, sei->base + GICP_SEMR(reg_idx));

And same nitpick comment :-)

> +static int mvebu_sei_irq_domain_alloc(struct irq_domain *domain,
> +				      unsigned int virq, unsigned int nr_irqs,
> +				      void *args)

I think the coding style says that arguments should be aligned, no ?

> +{
> +	struct mvebu_sei *sei = domain->host_data;
> +	struct irq_fwspec *fwspec = args;
> +	struct irq_chip *irq_chip;
> +	int sei_hwirq, hwirq;
> +	int ret;
> +
> +	/* Software only supports single allocations for now */
> +	if (nr_irqs != 1)
> +		return -ENOTSUPP;
> +
> +	if (domain == sei->ap_domain) {
> +		irq_chip = &mvebu_sei_ap_wired_irq_chip;
> +		hwirq = fwspec->param[0];
> +	} else {
> +		irq_chip = &mvebu_sei_cp_msi_irq_chip;
> +		spin_lock(&sei->cp_msi_lock);
> +		hwirq = bitmap_find_free_region(sei->cp_msi_bitmap, SEI_IRQ_NB,
> +						0);
> +		spin_unlock(&sei->cp_msi_lock);
> +		if (hwirq < 0)
> +			return -ENOSPC;
> +	}
> +
> +	sei_hwirq = mvebu_sei_domain_to_sei_irq(sei, domain, hwirq);
> +
> +	fwspec->fwnode = domain->parent->fwnode;
> +	fwspec->param_count = 3;
> +	fwspec->param[0] = GIC_SPI;
> +	fwspec->param[1] = sei_hwirq;
> +	fwspec->param[2] = IRQ_TYPE_EDGE_RISING;

Maybe it's me being confused, but I thought all SEI interrupts were
muxed together to a single SPI for the parent GIC. But here, you
allocate different SPIs at the GIC level. Intuitively, this doesn't
look good. Haven't you copy/pasted too much from the gicp driver, where
we have a 1:1 mapping between interrupts coming into the GICP and
interrupts signaled by the GICP to the GIC, while here we have a N:1
mapping, with N interrupts coming into the GICP_SEI, and only one
interrupt leaving the GICP_SEI to the GIC ?

> +static const struct irq_domain_ops mvebu_sei_ap_domain_ops = {
> +	.xlate = irq_domain_xlate_onecell,
> +	.alloc = mvebu_sei_irq_domain_alloc,
> +	.free = mvebu_sei_irq_domain_free,
> +};
> +
> +static const struct irq_domain_ops mvebu_sei_cp_domain_ops = {
> +	.xlate = irq_domain_xlate_twocell,
> +	.alloc = mvebu_sei_irq_domain_alloc,
> +	.free = mvebu_sei_irq_domain_free,
> +};

Why do you need two cells for the interrupts coming from the CP and
only one cell for the interrupts coming from the AP ?

For thermal in the AP, you do:

+					interrupt-parent = <&sei_wired_controller>;
+					interrupts = <18>;

i.e, you don't specify an interrupt type. For thermal in the CP, you do:

+				interrupts-extended =
+					<&CP110_LABEL(icu_sei) 116 IRQ_TYPE_LEVEL_HIGH>;

here you specify an interrupt type. I'm not sure why you have this
difference. Even more so because I think a SEI level interrupt is not
possible, since you only have a "SET" register and no "CLR" register.

Some guidance from Marc here might be useful perhaps.


> +static int mvebu_sei_probe(struct platform_device *pdev)
> +{
> +	struct device_node *node = pdev->dev.of_node, *parent, *child;
> +	struct irq_domain *parent_domain, *plat_domain;
> +	struct mvebu_sei *sei;
> +	const __be32 *property;
> +	u32 top_level_spi, size;
> +	int ret;
> +
> +	sei = devm_kzalloc(&pdev->dev, sizeof(*sei), GFP_KERNEL);
> +	if (!sei)
> +		return -ENOMEM;
> +
> +	sei->dev = &pdev->dev;
> +
> +	spin_lock_init(&sei->cp_msi_lock);
> +
> +	sei->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!sei->res) {
> +		dev_err(sei->dev, "Failed to retrieve SEI resource\n");
> +		return -ENODEV;
> +	}
> +
> +	sei->base = devm_ioremap(sei->dev, sei->res->start,
> +				 resource_size(sei->res));
> +	if (!sei->base) {
> +		dev_err(sei->dev, "Failed to remap SEI resource\n");
> +		return -ENODEV;
> +	}

Use devm_ioremap_resource() here, and remove the error handling of
platform_get_resource(), because it's already taken care of by
devm_ioremap_resource().

> +	/*
> +	 * Reserve the single (top-level) parent SPI IRQ from which all the
> +	 * interrupts handled by this driver will be signaled.
> +	 */
> +	top_level_spi = irq_of_parse_and_map(node, 0);
> +	if (top_level_spi <= 0) {
> +		dev_err(sei->dev, "Failed to retrieve top-level SPI IRQ\n");
> +		return -ENODEV;
> +	}

Rather than top_level_spi, something like parent_irq would make more
sense to me.

> +	irq_set_chained_handler(top_level_spi, mvebu_sei_handle_cascade_irq);
> +	irq_set_handler_data(top_level_spi, sei);
> +
> +	/*
> +	 * SEIs in the range [ 0; 20] are wired and come from the AP.
> +	 * SEIs in the range [21; 63] are CP SEI and are triggered through MSIs.
> +	 *
> +	 * Each SEI 'domain' is represented as a subnode.
> +	 */
> +
> +	/* Get a reference to the parent domain to create a hierarchy */
> +	parent = of_irq_find_parent(node);
> +	if (!parent) {
> +		dev_err(sei->dev, "Failed to find parent IRQ node\n");
> +		ret = -ENODEV;
> +		goto dispose_irq;
> +	}
> +
> +	parent_domain = irq_find_host(parent);
> +	if (!parent_domain) {
> +		dev_err(sei->dev, "Failed to find parent IRQ domain\n");
> +		ret = -ENODEV;
> +		goto dispose_irq;
> +	}
> +
> +	/* Create the 'wired' hierarchy */
> +	child = of_find_node_by_name(node, "sei-wired-controller");
> +	if (!child) {
> +		dev_err(sei->dev, "Missing 'sei-wired-controller' subnode\n");
> +		ret = -ENODEV;
> +		goto dispose_irq;
> +	}

Don't forget to of_node_put(child) once you're done using this DT node
reference.

> +
> +	property = of_get_property(child, "reg", &size);
> +	if (!property || size != (2 * sizeof(u32))) {
> +		dev_err(sei->dev, "Missing subnode 'reg' property\n");
> +		ret = -ENODEV;
> +		goto dispose_irq;
> +	}

As Rob said, I don't think the "reg" property is appropriate for this
usage.

> +	sei->ap_interrupts.first = be32_to_cpu(property[0]);
> +	sei->ap_interrupts.number = be32_to_cpu(property[1]);
> +	sei->ap_domain = irq_domain_create_hierarchy(parent_domain, 0,
> +						     sei->ap_interrupts.number,
> +						     of_node_to_fwnode(child),
> +						     &mvebu_sei_ap_domain_ops,
> +						     sei);
> +	if (!sei->ap_domain) {
> +		dev_err(sei->dev, "Failed to create AP IRQ domain\n");
> +		ret = -ENOMEM;
> +		goto dispose_irq;
> +	}
> +
> +	/* Create the 'MSI' hierarchy */
> +	child = of_find_node_by_name(node, "sei-msi-controller");
> +	if (!child) {
> +		dev_err(sei->dev, "Missing 'sei-msi-controller' subnode\n");
> +		ret = -ENODEV;
> +		goto remove_ap_domain;
> +	}

Ditto: missing of_node_put(child) somewhere below to balance
of_find_node_by_name().

> +	property = of_get_property(child, "reg", &size);
> +	if (!property || size != (2 * sizeof(u32))) {
> +		dev_err(sei->dev, "Missing subnode 'reg' property\n");
> +		ret = -ENODEV;
> +		goto remove_ap_domain;
> +	}
> +
> +	sei->cp_interrupts.first = be32_to_cpu(property[0]);
> +	sei->cp_interrupts.number = be32_to_cpu(property[1]);
> +	sei->cp_domain = irq_domain_create_hierarchy(parent_domain, 0,
> +						     sei->cp_interrupts.number,
> +						     of_node_to_fwnode(child),
> +						     &mvebu_sei_cp_domain_ops,
> +						     sei);
> +	if (!sei->cp_domain) {
> +		pr_err("Failed to create CPs IRQ domain\n");
> +		ret = -ENOMEM;
> +		goto remove_ap_domain;
> +	}
> +
> +	plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(child),
> +						     &mvebu_sei_msi_domain_info,
> +						     sei->cp_domain);
> +	if (!plat_domain) {
> +		pr_err("Failed to create CPs MSI domain\n");
> +		ret = -ENOMEM;
> +		goto remove_cp_domain;
> +	}



> +
> +	platform_set_drvdata(pdev, sei);
> +
> +	mvebu_sei_reset(sei);

Please do the reset *before* registering the IRQ domains, it's more
logical to have the HW ready and then expose it to Linux rather than
the opposite.

It would be nice to have the review from Marc on this driver,
especially on whether the SEI is properly modeled in terms of IRQ
domains;

> diff --git a/drivers/irqchip/irq-mvebu-sei.h b/drivers/irqchip/irq-mvebu-sei.h
> new file mode 100644
> index 000000000000..f0c12a441923
> --- /dev/null
> +++ b/drivers/irqchip/irq-mvebu-sei.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __MVEBU_SEI_H__
> +#define __MVEBU_SEI_H__
> +
> +#include <linux/types.h>
> +
> +struct device_node;
> +
> +int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
> +			    phys_addr_t *clr);
> +
> +#endif /* __MVEBU_SEI_H__ */

This header file can be removed if you drop mvebu_sei_get_doorbells(),
as suggested above.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 10/17] irqchip/irq-mvebu-sei: add new driver for Marvell SEI
  2018-05-02  9:17     ` Thomas Petazzoni
@ 2018-05-02 15:56       ` Thomas Petazzoni
  -1 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-05-02 15:56 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hello,

On Wed, 2 May 2018 11:17:44 +0200, Thomas Petazzoni wrote:

> > +static const struct irq_domain_ops mvebu_sei_ap_domain_ops = {
> > +	.xlate = irq_domain_xlate_onecell,
> > +	.alloc = mvebu_sei_irq_domain_alloc,
> > +	.free = mvebu_sei_irq_domain_free,
> > +};
> > +
> > +static const struct irq_domain_ops mvebu_sei_cp_domain_ops = {
> > +	.xlate = irq_domain_xlate_twocell,
> > +	.alloc = mvebu_sei_irq_domain_alloc,
> > +	.free = mvebu_sei_irq_domain_free,
> > +};  
> 
> Why do you need two cells for the interrupts coming from the CP and
> only one cell for the interrupts coming from the AP ?
> 
> For thermal in the AP, you do:
> 
> +					interrupt-parent = <&sei_wired_controller>;
> +					interrupts = <18>;
> 
> i.e, you don't specify an interrupt type. For thermal in the CP, you do:
> 
> +				interrupts-extended =
> +					<&CP110_LABEL(icu_sei) 116 IRQ_TYPE_LEVEL_HIGH>;
> 
> here you specify an interrupt type. I'm not sure why you have this
> difference. Even more so because I think a SEI level interrupt is not
> possible, since you only have a "SET" register and no "CLR" register.

OK, my comment is not very correct here, I'm comparing apple to
oranges. The former its an interrupt directly pointing to the GICP_SEI,
while the latter is an interrupt of the ICU, which itself will notify
the GICP_SEI through an MSI.

However, I'm still confused as to why you have .xlate =
irq_domain_xlate_twocell for the mvebu_sei_cp_domain_ops. I think there
is no need for ->xlate() call back here because it's going to be a MSI
domain.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* [PATCH 10/17] irqchip/irq-mvebu-sei: add new driver for Marvell SEI
@ 2018-05-02 15:56       ` Thomas Petazzoni
  0 siblings, 0 replies; 92+ messages in thread
From: Thomas Petazzoni @ 2018-05-02 15:56 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Wed, 2 May 2018 11:17:44 +0200, Thomas Petazzoni wrote:

> > +static const struct irq_domain_ops mvebu_sei_ap_domain_ops = {
> > +	.xlate = irq_domain_xlate_onecell,
> > +	.alloc = mvebu_sei_irq_domain_alloc,
> > +	.free = mvebu_sei_irq_domain_free,
> > +};
> > +
> > +static const struct irq_domain_ops mvebu_sei_cp_domain_ops = {
> > +	.xlate = irq_domain_xlate_twocell,
> > +	.alloc = mvebu_sei_irq_domain_alloc,
> > +	.free = mvebu_sei_irq_domain_free,
> > +};  
> 
> Why do you need two cells for the interrupts coming from the CP and
> only one cell for the interrupts coming from the AP ?
> 
> For thermal in the AP, you do:
> 
> +					interrupt-parent = <&sei_wired_controller>;
> +					interrupts = <18>;
> 
> i.e, you don't specify an interrupt type. For thermal in the CP, you do:
> 
> +				interrupts-extended =
> +					<&CP110_LABEL(icu_sei) 116 IRQ_TYPE_LEVEL_HIGH>;
> 
> here you specify an interrupt type. I'm not sure why you have this
> difference. Even more so because I think a SEI level interrupt is not
> possible, since you only have a "SET" register and no "CLR" register.

OK, my comment is not very correct here, I'm comparing apple to
oranges. The former its an interrupt directly pointing to the GICP_SEI,
while the latter is an interrupt of the ICU, which itself will notify
the GICP_SEI through an MSI.

However, I'm still confused as to why you have .xlate =
irq_domain_xlate_twocell for the mvebu_sei_cp_domain_ops. I think there
is no need for ->xlate() call back here because it's going to be a MSI
domain.

Best regards,

Thomas
-- 
Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 04/17] irqchip/irq-mvebu-icu: fix wrong user data retrieval
  2018-04-30 13:49     ` Thomas Petazzoni
@ 2018-05-03 14:57       ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-05-03 14:57 UTC (permalink / raw)
  To: Thomas Petazzoni
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hi Thomas,

On Mon, 30 Apr 2018 15:49:13 +0200, Thomas Petazzoni
<thomas.petazzoni@bootlin.com> wrote:

> Hello,
> 
> In the title, I think "user data" is not really appropriate. "private
> date" or "device private data" maybe ?

Sure, I will change to "fix wrong private data retrieval".

> 
> On Sat, 21 Apr 2018 15:55:24 +0200, Miquel Raynal wrote:
> > The irq_domain structure has an host_data pointer that just stores user
> > data. It is meant to not be touched by the IRQ core. However, when it
> > comes to MSI, the MSI layer adds its own private data there with a
> > structure that also has a host_data pointer.
> > 
> > Because this IRQ domain is an MSI domain, to access user data we should
> > do a d->host_data->host_data, also wrapped as
> > 'platform_msi_get_host_data()'.
> > 
> > This bug was lying there silently because the 'icu' structure retrieved
> > this way was just called by dev_err(), only producing a
> > '(NULL device *):' output on the console.
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>  
> 
> Otherwise:
> 
> Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thanks,
Miquèl

-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 04/17] irqchip/irq-mvebu-icu: fix wrong user data retrieval
@ 2018-05-03 14:57       ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-05-03 14:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

On Mon, 30 Apr 2018 15:49:13 +0200, Thomas Petazzoni
<thomas.petazzoni@bootlin.com> wrote:

> Hello,
> 
> In the title, I think "user data" is not really appropriate. "private
> date" or "device private data" maybe ?

Sure, I will change to "fix wrong private data retrieval".

> 
> On Sat, 21 Apr 2018 15:55:24 +0200, Miquel Raynal wrote:
> > The irq_domain structure has an host_data pointer that just stores user
> > data. It is meant to not be touched by the IRQ core. However, when it
> > comes to MSI, the MSI layer adds its own private data there with a
> > structure that also has a host_data pointer.
> > 
> > Because this IRQ domain is an MSI domain, to access user data we should
> > do a d->host_data->host_data, also wrapped as
> > 'platform_msi_get_host_data()'.
> > 
> > This bug was lying there silently because the 'icu' structure retrieved
> > this way was just called by dev_err(), only producing a
> > '(NULL device *):' output on the console.
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>  
> 
> Otherwise:
> 
> Reviewed-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>

Thanks,
Miqu?l

-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 06/17] irqchip/irq-mvebu-icu: switch to regmap
  2018-04-30 13:53     ` Thomas Petazzoni
@ 2018-05-03 15:05       ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-05-03 15:05 UTC (permalink / raw)
  To: Thomas Petazzoni
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hi Thomas, Gregory,

On Mon, 30 Apr 2018 15:53:52 +0200, Thomas Petazzoni
<thomas.petazzoni@bootlin.com> wrote:

> Hello,
> 
> On Sat, 21 Apr 2018 15:55:26 +0200, Miquel Raynal wrote:
> > The ICU DT nodes have now the 'syscon' compatible, we can switch to  
> 
> have now -> now have
> 
> > regmap before splitting the code to support multiple platform devices to
> > be probed (one for the ICU, one per interrupt group).
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>  
> 
> As I explained in the review of PATCH 03/17, I think we could simply
> create the regmap in the ->probe() of the parent device, instead of
> using the "syscon" property, which is mainly useful when there is no
> parent device.

This is a much better idea than adding the 'syscon' compatible. I will
work on it.

> 
> The rest of the conversion to regmap looks good otherwise.
> 
> Best regards,
> 
> Thomas

Thanks,
Miquèl

-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 06/17] irqchip/irq-mvebu-icu: switch to regmap
@ 2018-05-03 15:05       ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-05-03 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas, Gregory,

On Mon, 30 Apr 2018 15:53:52 +0200, Thomas Petazzoni
<thomas.petazzoni@bootlin.com> wrote:

> Hello,
> 
> On Sat, 21 Apr 2018 15:55:26 +0200, Miquel Raynal wrote:
> > The ICU DT nodes have now the 'syscon' compatible, we can switch to  
> 
> have now -> now have
> 
> > regmap before splitting the code to support multiple platform devices to
> > be probed (one for the ICU, one per interrupt group).
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>  
> 
> As I explained in the review of PATCH 03/17, I think we could simply
> create the regmap in the ->probe() of the parent device, instead of
> using the "syscon" property, which is mainly useful when there is no
> parent device.

This is a much better idea than adding the 'syscon' compatible. I will
work on it.

> 
> The rest of the conversion to regmap looks good otherwise.
> 
> Best regards,
> 
> Thomas

Thanks,
Miqu?l

-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 09/17] irqchip/irq-mvebu-icu: support ICU subnodes
  2018-05-02  8:13     ` Thomas Petazzoni
@ 2018-05-04  8:32       ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-05-04  8:32 UTC (permalink / raw)
  To: Thomas Petazzoni
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hi Thomas,

On Wed, 2 May 2018 10:13:00 +0200, Thomas Petazzoni
<thomas.petazzoni@bootlin.com> wrote:

> Hello Miquèl,
> 
> On Sat, 21 Apr 2018 15:55:29 +0200, Miquel Raynal wrote:
> > Introduce new bindings for the ICU.  
> 
> Perhaps this should explain *why* we need new bindings.

Sure, I changed the whole message by:

    The ICU can handle several type of interrupt, each of them being
    handled differently on AP side. On CP side, the ICU should be able
    to make the distinction between each interrupt group by pointing to
    the right parent.
    
    This is done through the introduction of new bindings, presenting
    the ICU node as the parent of multiple ICU sub-nodes, each of them
    being an interrupt type with a different interrupt parent. ICU
    interrupt 'clients' now directly point to the right sub-node,
    avoiding the need for the extra ICU_GRP_* parameter.
    
    ICU subnodes are probed automatically with
    devm_platform_populate(). If the node as no child, the probe
    function for NSRs will still be called 'manually' in order to
    preserve backward compatibility with DT using the old binding.
    
> 
> > Each DT subnode of the ICU represents a type of interrupt that should
> > be handled separately. Add the possibility for the ICU to have subnodes
> > and probe each of them automatically with devm_platform_populate(). If
> > the node as no child, the probe function for NSRs will still be called
> > 'manually'.  
> 
>  ... in order to preserve backward compatibility with Device Trees
>  using the old binding.

Added, see above.

> 
> > +static struct mvebu_icu *mvebu_dev_get_drvdata(struct platform_device *pdev)  
> 
> The function should be prefixed by mvebu_icu_, not just mvebu_.

Changed.

> 
> > +{
> > +	struct mvebu_icu *icu;
> > +
> > +	icu = dev_get_drvdata(&pdev->dev);
> > +	if (icu) {
> > +		/* Legacy bindings: get the device data */  
> 
> I find this comment weird, because it doesn't document what the test
> just below is doing.

Refactored a bit the comments in this section.

> 
> > +		if (!icu->legacy_bindings)
> > +			return ERR_PTR(-EINVAL);
> > +	} else {
> > +		/* New bindings: get the parent device (ICU) data */
> > +		icu = dev_get_drvdata(pdev->dev.parent);
> > +		if (!icu)
> > +			return ERR_PTR(-ENODEV);
> > +		if (icu->legacy_bindings)
> > +			return ERR_PTR(-EINVAL);
> > +	}  
> 
> 
> > @@ -144,7 +170,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
> >  		goto free_irqd;
> >  	}
> >  
> > -	icu_irqd->icu_group = fwspec->param[0];
> > +	if (icu->legacy_bindings)
> > +		icu_irqd->icu_group = fwspec->param[0];
> > +	else
> > +		icu_irqd->icu_group = ICU_GRP_NSR;  
> 
> In practice here fwspec->param[0] is always going to be equal to
> ICU_GRP_NSR, but OK, the test makes sense as in a future commit, the
> "else" case will be changed to support SEIs.
> 
> > +static const struct of_device_id mvebu_icu_nsr_of_match[] = {
> > +	{ .compatible = "marvell,cp110-icu-nsr", },
> > +	{},
> > +};
> > +
> > +static struct platform_driver mvebu_icu_nsr_driver = {
> > +	.probe  = mvebu_icu_nsr_probe,
> > +	.driver = {
> > +		.name = "mvebu-icu-nsr",
> > +		.of_match_table = mvebu_icu_nsr_of_match,
> > +	},
> > +};
> > +builtin_platform_driver(mvebu_icu_nsr_driver);  
> 
> I'm not sure why you call this icu_nsr here, and change it later to
> icu_subset. Wouldn't it make sense to call it right away with the final
> name ? Note that this is not a very strong request to change this
> aspect, I'm fine with how it's done today, it's just that I would have
> done it differently.

I thought calling it icu_subset right now would not be very clear as
there are not "ICU subset" other than NSR interrupts, but I changed it,
this is not a big deal.

> 
> Other than that, looks good to me.
> 
> Thomas

Thanks for the review,
Miquèl


-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 09/17] irqchip/irq-mvebu-icu: support ICU subnodes
@ 2018-05-04  8:32       ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-05-04  8:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

On Wed, 2 May 2018 10:13:00 +0200, Thomas Petazzoni
<thomas.petazzoni@bootlin.com> wrote:

> Hello Miqu?l,
> 
> On Sat, 21 Apr 2018 15:55:29 +0200, Miquel Raynal wrote:
> > Introduce new bindings for the ICU.  
> 
> Perhaps this should explain *why* we need new bindings.

Sure, I changed the whole message by:

    The ICU can handle several type of interrupt, each of them being
    handled differently on AP side. On CP side, the ICU should be able
    to make the distinction between each interrupt group by pointing to
    the right parent.
    
    This is done through the introduction of new bindings, presenting
    the ICU node as the parent of multiple ICU sub-nodes, each of them
    being an interrupt type with a different interrupt parent. ICU
    interrupt 'clients' now directly point to the right sub-node,
    avoiding the need for the extra ICU_GRP_* parameter.
    
    ICU subnodes are probed automatically with
    devm_platform_populate(). If the node as no child, the probe
    function for NSRs will still be called 'manually' in order to
    preserve backward compatibility with DT using the old binding.
    
> 
> > Each DT subnode of the ICU represents a type of interrupt that should
> > be handled separately. Add the possibility for the ICU to have subnodes
> > and probe each of them automatically with devm_platform_populate(). If
> > the node as no child, the probe function for NSRs will still be called
> > 'manually'.  
> 
>  ... in order to preserve backward compatibility with Device Trees
>  using the old binding.

Added, see above.

> 
> > +static struct mvebu_icu *mvebu_dev_get_drvdata(struct platform_device *pdev)  
> 
> The function should be prefixed by mvebu_icu_, not just mvebu_.

Changed.

> 
> > +{
> > +	struct mvebu_icu *icu;
> > +
> > +	icu = dev_get_drvdata(&pdev->dev);
> > +	if (icu) {
> > +		/* Legacy bindings: get the device data */  
> 
> I find this comment weird, because it doesn't document what the test
> just below is doing.

Refactored a bit the comments in this section.

> 
> > +		if (!icu->legacy_bindings)
> > +			return ERR_PTR(-EINVAL);
> > +	} else {
> > +		/* New bindings: get the parent device (ICU) data */
> > +		icu = dev_get_drvdata(pdev->dev.parent);
> > +		if (!icu)
> > +			return ERR_PTR(-ENODEV);
> > +		if (icu->legacy_bindings)
> > +			return ERR_PTR(-EINVAL);
> > +	}  
> 
> 
> > @@ -144,7 +170,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
> >  		goto free_irqd;
> >  	}
> >  
> > -	icu_irqd->icu_group = fwspec->param[0];
> > +	if (icu->legacy_bindings)
> > +		icu_irqd->icu_group = fwspec->param[0];
> > +	else
> > +		icu_irqd->icu_group = ICU_GRP_NSR;  
> 
> In practice here fwspec->param[0] is always going to be equal to
> ICU_GRP_NSR, but OK, the test makes sense as in a future commit, the
> "else" case will be changed to support SEIs.
> 
> > +static const struct of_device_id mvebu_icu_nsr_of_match[] = {
> > +	{ .compatible = "marvell,cp110-icu-nsr", },
> > +	{},
> > +};
> > +
> > +static struct platform_driver mvebu_icu_nsr_driver = {
> > +	.probe  = mvebu_icu_nsr_probe,
> > +	.driver = {
> > +		.name = "mvebu-icu-nsr",
> > +		.of_match_table = mvebu_icu_nsr_of_match,
> > +	},
> > +};
> > +builtin_platform_driver(mvebu_icu_nsr_driver);  
> 
> I'm not sure why you call this icu_nsr here, and change it later to
> icu_subset. Wouldn't it make sense to call it right away with the final
> name ? Note that this is not a very strong request to change this
> aspect, I'm fine with how it's done today, it's just that I would have
> done it differently.

I thought calling it icu_subset right now would not be very clear as
there are not "ICU subset" other than NSR interrupts, but I changed it,
this is not a big deal.

> 
> Other than that, looks good to me.
> 
> Thomas

Thanks for the review,
Miqu?l


-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH 10/17] irqchip/irq-mvebu-sei: add new driver for Marvell SEI
  2018-05-02  9:17     ` Thomas Petazzoni
@ 2018-05-18 13:22       ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-05-18 13:22 UTC (permalink / raw)
  To: Thomas Petazzoni
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Rob Herring, Thomas Gleixner, Hanna Hawa, linux-arm-kernel,
	Sebastian Hesselbarth

Hi Thomas,

On Wed, 2 May 2018 11:17:44 +0200, Thomas Petazzoni
<thomas.petazzoni@bootlin.com> wrote:

> Hello,
> 
> On Sat, 21 Apr 2018 15:55:30 +0200, Miquel Raynal wrote:
> 
> > diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> > index 5ed465ab1c76..6b5b75cb4694 100644
> > --- a/drivers/irqchip/Makefile
> > +++ b/drivers/irqchip/Makefile
> > @@ -73,6 +73,7 @@ obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
> >  obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
> >  obj-$(CONFIG_MSCC_OCELOT_IRQ)		+= irq-mscc-ocelot.o
> >  obj-$(CONFIG_MVEBU_GICP)		+= irq-mvebu-gicp.o
> > +obj-$(CONFIG_MVEBU_SEI)			+= irq-mvebu-sei.o
> >  obj-$(CONFIG_MVEBU_ICU)			+= irq-mvebu-icu.o
> >  obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
> >  obj-$(CONFIG_MVEBU_PIC)			+= irq-mvebu-pic.o  
> 
> Alphabetic ordering would put SEI after PIC I guess :)

Sure.

> 
> > diff --git a/drivers/irqchip/irq-mvebu-sei.c b/drivers/irqchip/irq-mvebu-sei.c
> > new file mode 100644
> > index 000000000000..5c12c74e3f09
> > --- /dev/null
> > +++ b/drivers/irqchip/irq-mvebu-sei.c
> > @@ -0,0 +1,449 @@
> > +// SPDX-License-Identifier: GPL-2.0 OR X11  
> 
> License for code is GPL-2.0 only. We use GPL-2.0 OR X11 for Device
> Trees.

I did not know, thanks for the explanation.

> 
> > +#define pr_fmt(fmt) "mvebu-sei: " fmt
> > +
> > +#include <linux/irq.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/irqchip/chained_irq.h>
> > +#include <linux/irqdomain.h>
> > +#include <linux/kernel.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/msi.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/irqchip.h>
> > +
> > +#include <dt-bindings/interrupt-controller/arm-gic.h>
> > +
> > +#define GICP_SET_SEI_OFFSET	0x30
> > +#define GICP_CLR_SEI_OFFSET	GICP_SET_SEI_OFFSET  
> 
> Why do you have this concept of set/clr if there is only one register ?
> I assume that if there is only a "set" register, it means that SEI
> interrupts can only be edge triggered, contrary to NSR interrupts,
> which have separate set/clr to support level-triggered interrupts.
> 
> Having only a "set" offset means that we can rely on the existing
> "struct msi_msg" to convey both the MSI doorbell address and payload,
> and we don't need the mvebu_gicp_get_doorbells() hack.

I misunderstood the specification at first (when copying code from the
gicp driver), and then continued in my mistake. I removed the whole
doorbell thing.

> 
> > +/* Cause register */
> > +#define GICP_SECR(idx)		(0x0  + (idx * 0x4))
> > +/* Mask register */
> > +#define GICP_SEMR(idx)		(0x20 + (idx * 0x4))  
> 
> Minor nit: order register definitions by order of increasing offset,
> i.e the GICP_SET_SEI_OFFSET should be defined here.

Ok.

> 
> > +#define SEI_IRQ_NB_PER_REG	32
> > +#define SEI_IRQ_REG_NB		2  
> 
> s/NB/COUNT/

Changed.

> 
> > +#define SEI_IRQ_NB		(SEI_IRQ_NB_PER_REG * SEI_IRQ_REG_NB)  
> 
> Ditto.
> 
> > +#define SEI_IRQ_REG_IDX(irq_id)	(irq_id / SEI_IRQ_NB_PER_REG)
> > +#define SEI_IRQ_REG_BIT(irq_id)	(irq_id % SEI_IRQ_NB_PER_REG)
> > +
> > +struct mvebu_sei_interrupt_range {
> > +	u32 first;
> > +	u32 number;
> > +};
> > +
> > +struct mvebu_sei {
> > +	struct device *dev;
> > +	void __iomem *base;
> > +	struct resource *res;
> > +	struct irq_domain *ap_domain;
> > +	struct irq_domain *cp_domain;
> > +	struct mvebu_sei_interrupt_range ap_interrupts;
> > +	struct mvebu_sei_interrupt_range cp_interrupts;
> > +	/* Lock on MSI allocations/releases */
> > +	spinlock_t cp_msi_lock;
> > +	DECLARE_BITMAP(cp_msi_bitmap, SEI_IRQ_NB);
> > +};
> > +
> > +static int mvebu_sei_domain_to_sei_irq(struct mvebu_sei *sei,
> > +				       struct irq_domain *domain,
> > +				       irq_hw_number_t hwirq)
> > +{
> > +	if (domain == sei->ap_domain)
> > +		return sei->ap_interrupts.first + hwirq;
> > +	else
> > +		return sei->cp_interrupts.first + hwirq;  
> 
> I am not entirely clear whether we need subnodes or not in this
> binding, but I guess we do because we have one subset of the interrupts
> that are wired interrupts, and another part that are MSI triggered.
> 
> Perhaps this is one aspect on which Marc Zyngier can comment ?
> 
> > +static void mvebu_sei_reset(struct mvebu_sei *sei)
> > +{
> > +	u32 reg_idx;
> > +
> > +	for (reg_idx = 0; reg_idx < SEI_IRQ_REG_NB; reg_idx++) {
> > +		/* Clear all cause bits */
> > +		writel(0xFFFFFFFF, sei->base + GICP_SECR(reg_idx));
> > +		/* Enable all interrupts */
> > +		writel(0, sei->base + GICP_SEMR(reg_idx));  
> 
> Enabling interrupts by default ? This looks weird. They should only be
> enabled... when enabled.

That's right, no need to enable them here.

> 
> > +int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
> > +			    phys_addr_t *clr)
> > +{
> > +	struct platform_device *pdev;
> > +	struct mvebu_sei *sei;
> > +
> > +	pdev = of_find_device_by_node(dn->parent);
> > +	if (!pdev)
> > +		return -ENODEV;
> > +
> > +	sei = platform_get_drvdata(pdev);
> > +	if (!sei)
> > +		return -ENODEV;
> > +
> > +	*set = (phys_addr_t)(sei->res->start + GICP_SET_SEI_OFFSET);
> > +	*clr = (phys_addr_t)(sei->res->start + GICP_CLR_SEI_OFFSET);
> > +
> > +	return 0;
> > +}  
> 
> As I said above, I believe this hack is not needed, because SEIs are
> edge-triggered, and we have a single SET_SEI_OFFSET MSI doorbell
> address to convey, which makes "struct msi_msg" as it is today
> sufficient.

Removed.

> 
> > +static void mvebu_sei_mask_irq(struct irq_data *d)
> > +{
> > +	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
> > +	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);  
> 
> This doesn't look right. The d->hwirq is relative to the beginning of
> the domain, while you should use sei_irq here. For example, the SEI
> n°32 (first interrupt in the second register) will have d->hwirq = 11,
> because it is the 11th SEI interrupt for the CP. So here, you will
> conclude that reg_idx = 0, while it should be reg_idx = 1.

This is true. I did not saw it because... well... all interrupts were
enabled by default.

> 
> > +	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
> > +	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
> > +	u32 reg;
> > +
> > +	/* 1 disables the interrupt */
> > +	reg =  readl(sei->base + GICP_SEMR(reg_idx));
> > +	writel(reg | irq_mask, sei->base + GICP_SEMR(reg_idx));  
> 
> Personal taste here, but I prefer:
> 
> 	reg =  readl(sei->base + GICP_SEMR(reg_idx));
> 	reg |= BIT(SEI_IRQ_REG_BIT(sei_irq));
> 	writel(reg, sei->base + GICP_SEMR(reg_idx));

No problem.

> 
> > +static void mvebu_sei_unmask_irq(struct irq_data *d)
> > +{
> > +	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
> > +	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);  
> 
> Same mistake as above I believe.
> 
> > +	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
> > +	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
> > +	u32 reg;
> > +
> > +	/* 0 enables the interrupt */
> > +	reg = readl(sei->base + GICP_SEMR(reg_idx));
> > +	writel(reg & ~irq_mask, sei->base + GICP_SEMR(reg_idx));  
> 
> And same nitpick comment :-)
> 
> > +static int mvebu_sei_irq_domain_alloc(struct irq_domain *domain,
> > +				      unsigned int virq, unsigned int nr_irqs,
> > +				      void *args)  
> 
> I think the coding style says that arguments should be aligned, no ?
> 
> > +{
> > +	struct mvebu_sei *sei = domain->host_data;
> > +	struct irq_fwspec *fwspec = args;
> > +	struct irq_chip *irq_chip;
> > +	int sei_hwirq, hwirq;
> > +	int ret;
> > +
> > +	/* Software only supports single allocations for now */
> > +	if (nr_irqs != 1)
> > +		return -ENOTSUPP;
> > +
> > +	if (domain == sei->ap_domain) {
> > +		irq_chip = &mvebu_sei_ap_wired_irq_chip;
> > +		hwirq = fwspec->param[0];
> > +	} else {
> > +		irq_chip = &mvebu_sei_cp_msi_irq_chip;
> > +		spin_lock(&sei->cp_msi_lock);
> > +		hwirq = bitmap_find_free_region(sei->cp_msi_bitmap, SEI_IRQ_NB,
> > +						0);
> > +		spin_unlock(&sei->cp_msi_lock);
> > +		if (hwirq < 0)
> > +			return -ENOSPC;
> > +	}
> > +
> > +	sei_hwirq = mvebu_sei_domain_to_sei_irq(sei, domain, hwirq);
> > +
> > +	fwspec->fwnode = domain->parent->fwnode;
> > +	fwspec->param_count = 3;
> > +	fwspec->param[0] = GIC_SPI;
> > +	fwspec->param[1] = sei_hwirq;
> > +	fwspec->param[2] = IRQ_TYPE_EDGE_RISING;  
> 
> Maybe it's me being confused, but I thought all SEI interrupts were
> muxed together to a single SPI for the parent GIC. But here, you
> allocate different SPIs at the GIC level. Intuitively, this doesn't
> look good. Haven't you copy/pasted too much from the gicp driver, where
> we have a 1:1 mapping between interrupts coming into the GICP and
> interrupts signaled by the GICP to the GIC, while here we have a N:1
> mapping, with N interrupts coming into the GICP_SEI, and only one
> interrupt leaving the GICP_SEI to the GIC ?

I am a bit in troubles understanding what fwspec->param[1] exactly
means here. I suppose I should s/sei_hwirq/0/ as there is only one SPI
interrupt to refer to?

Maybe Marc can comment on this too?

> 
> > +static const struct irq_domain_ops mvebu_sei_ap_domain_ops = {
> > +	.xlate = irq_domain_xlate_onecell,
> > +	.alloc = mvebu_sei_irq_domain_alloc,
> > +	.free = mvebu_sei_irq_domain_free,
> > +};
> > +
> > +static const struct irq_domain_ops mvebu_sei_cp_domain_ops = {
> > +	.xlate = irq_domain_xlate_twocell,
> > +	.alloc = mvebu_sei_irq_domain_alloc,
> > +	.free = mvebu_sei_irq_domain_free,
> > +};  
> 
> Why do you need two cells for the interrupts coming from the CP and
> only one cell for the interrupts coming from the AP ?
> 
> For thermal in the AP, you do:
> 
> +					interrupt-parent = <&sei_wired_controller>;
> +					interrupts = <18>;
> 
> i.e, you don't specify an interrupt type. For thermal in the CP, you do:
> 
> +				interrupts-extended =
> +					<&CP110_LABEL(icu_sei) 116 IRQ_TYPE_LEVEL_HIGH>;
> 
> here you specify an interrupt type. I'm not sure why you have this
> difference. Even more so because I think a SEI level interrupt is not
> possible, since you only have a "SET" register and no "CLR" register.

and then you wrote:

<quote>
> OK, my comment is not very correct here, I'm comparing apple to
> oranges. The former its an interrupt directly pointing to the GICP_SEI,
> while the latter is an interrupt of the ICU, which itself will notify
> the GICP_SEI through an MSI.

> However, I'm still confused as to why you have .xlate =
> irq_domain_xlate_twocell for the mvebu_sei_cp_domain_ops. I think there
> is no need for ->xlate() call back here because it's going to be a MSI
> domain.
</quote>

For thermal in the AP I should probably add an IRQ_TYPE_LEVEL_HIGH in
order to describe properly the interrupt (wired).

I also removed the .xlate entry for the CP domain, I was not sure it
was useless for MSI but it looks it is.

> 
> Some guidance from Marc here might be useful perhaps.
> 
> 
> > +static int mvebu_sei_probe(struct platform_device *pdev)
> > +{
> > +	struct device_node *node = pdev->dev.of_node, *parent, *child;
> > +	struct irq_domain *parent_domain, *plat_domain;
> > +	struct mvebu_sei *sei;
> > +	const __be32 *property;
> > +	u32 top_level_spi, size;
> > +	int ret;
> > +
> > +	sei = devm_kzalloc(&pdev->dev, sizeof(*sei), GFP_KERNEL);
> > +	if (!sei)
> > +		return -ENOMEM;
> > +
> > +	sei->dev = &pdev->dev;
> > +
> > +	spin_lock_init(&sei->cp_msi_lock);
> > +
> > +	sei->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	if (!sei->res) {
> > +		dev_err(sei->dev, "Failed to retrieve SEI resource\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	sei->base = devm_ioremap(sei->dev, sei->res->start,
> > +				 resource_size(sei->res));
> > +	if (!sei->base) {
> > +		dev_err(sei->dev, "Failed to remap SEI resource\n");
> > +		return -ENODEV;
> > +	}  
> 
> Use devm_ioremap_resource() here, and remove the error handling of
> platform_get_resource(), because it's already taken care of by
> devm_ioremap_resource().

Good tip, I'll remember.

> 
> > +	/*
> > +	 * Reserve the single (top-level) parent SPI IRQ from which all the
> > +	 * interrupts handled by this driver will be signaled.
> > +	 */
> > +	top_level_spi = irq_of_parse_and_map(node, 0);
> > +	if (top_level_spi <= 0) {
> > +		dev_err(sei->dev, "Failed to retrieve top-level SPI IRQ\n");
> > +		return -ENODEV;
> > +	}  
> 
> Rather than top_level_spi, something like parent_irq would make more
> sense to me.

Renamed.

> 
> > +	irq_set_chained_handler(top_level_spi, mvebu_sei_handle_cascade_irq);
> > +	irq_set_handler_data(top_level_spi, sei);
> > +
> > +	/*
> > +	 * SEIs in the range [ 0; 20] are wired and come from the AP.
> > +	 * SEIs in the range [21; 63] are CP SEI and are triggered through MSIs.
> > +	 *
> > +	 * Each SEI 'domain' is represented as a subnode.
> > +	 */
> > +
> > +	/* Get a reference to the parent domain to create a hierarchy */
> > +	parent = of_irq_find_parent(node);
> > +	if (!parent) {
> > +		dev_err(sei->dev, "Failed to find parent IRQ node\n");
> > +		ret = -ENODEV;
> > +		goto dispose_irq;
> > +	}
> > +
> > +	parent_domain = irq_find_host(parent);
> > +	if (!parent_domain) {
> > +		dev_err(sei->dev, "Failed to find parent IRQ domain\n");
> > +		ret = -ENODEV;
> > +		goto dispose_irq;
> > +	}
> > +
> > +	/* Create the 'wired' hierarchy */
> > +	child = of_find_node_by_name(node, "sei-wired-controller");
> > +	if (!child) {
> > +		dev_err(sei->dev, "Missing 'sei-wired-controller' subnode\n");
> > +		ret = -ENODEV;
> > +		goto dispose_irq;
> > +	}  
> 
> Don't forget to of_node_put(child) once you're done using this DT node
> reference.

Ok.

> 
> > +
> > +	property = of_get_property(child, "reg", &size);
> > +	if (!property || size != (2 * sizeof(u32))) {
> > +		dev_err(sei->dev, "Missing subnode 'reg' property\n");
> > +		ret = -ENODEV;
> > +		goto dispose_irq;
> > +	}  
> 
> As Rob said, I don't think the "reg" property is appropriate for this
> usage.

I will change.

> 
> > +	sei->ap_interrupts.first = be32_to_cpu(property[0]);
> > +	sei->ap_interrupts.number = be32_to_cpu(property[1]);
> > +	sei->ap_domain = irq_domain_create_hierarchy(parent_domain, 0,
> > +						     sei->ap_interrupts.number,
> > +						     of_node_to_fwnode(child),
> > +						     &mvebu_sei_ap_domain_ops,
> > +						     sei);
> > +	if (!sei->ap_domain) {
> > +		dev_err(sei->dev, "Failed to create AP IRQ domain\n");
> > +		ret = -ENOMEM;
> > +		goto dispose_irq;
> > +	}
> > +
> > +	/* Create the 'MSI' hierarchy */
> > +	child = of_find_node_by_name(node, "sei-msi-controller");
> > +	if (!child) {
> > +		dev_err(sei->dev, "Missing 'sei-msi-controller' subnode\n");
> > +		ret = -ENODEV;
> > +		goto remove_ap_domain;
> > +	}  
> 
> Ditto: missing of_node_put(child) somewhere below to balance
> of_find_node_by_name().

Ok.

> 
> > +	property = of_get_property(child, "reg", &size);
> > +	if (!property || size != (2 * sizeof(u32))) {
> > +		dev_err(sei->dev, "Missing subnode 'reg' property\n");
> > +		ret = -ENODEV;
> > +		goto remove_ap_domain;
> > +	}
> > +
> > +	sei->cp_interrupts.first = be32_to_cpu(property[0]);
> > +	sei->cp_interrupts.number = be32_to_cpu(property[1]);
> > +	sei->cp_domain = irq_domain_create_hierarchy(parent_domain, 0,
> > +						     sei->cp_interrupts.number,
> > +						     of_node_to_fwnode(child),
> > +						     &mvebu_sei_cp_domain_ops,
> > +						     sei);
> > +	if (!sei->cp_domain) {
> > +		pr_err("Failed to create CPs IRQ domain\n");
> > +		ret = -ENOMEM;
> > +		goto remove_ap_domain;
> > +	}
> > +
> > +	plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(child),
> > +						     &mvebu_sei_msi_domain_info,
> > +						     sei->cp_domain);
> > +	if (!plat_domain) {
> > +		pr_err("Failed to create CPs MSI domain\n");
> > +		ret = -ENOMEM;
> > +		goto remove_cp_domain;
> > +	}  
> 
> 
> 
> > +
> > +	platform_set_drvdata(pdev, sei);
> > +
> > +	mvebu_sei_reset(sei);  
> 
> Please do the reset *before* registering the IRQ domains, it's more
> logical to have the HW ready and then expose it to Linux rather than
> the opposite.

Sure.

> 
> It would be nice to have the review from Marc on this driver,
> especially on whether the SEI is properly modeled in terms of IRQ
> domains;
> 
> > diff --git a/drivers/irqchip/irq-mvebu-sei.h b/drivers/irqchip/irq-mvebu-sei.h
> > new file mode 100644
> > index 000000000000..f0c12a441923
> > --- /dev/null
> > +++ b/drivers/irqchip/irq-mvebu-sei.h
> > @@ -0,0 +1,12 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef __MVEBU_SEI_H__
> > +#define __MVEBU_SEI_H__
> > +
> > +#include <linux/types.h>
> > +
> > +struct device_node;
> > +
> > +int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
> > +			    phys_addr_t *clr);
> > +
> > +#endif /* __MVEBU_SEI_H__ */  
> 
> This header file can be removed if you drop mvebu_sei_get_doorbells(),
> as suggested above.

Indeed.

> 
> Best regards,
> 
> Thomas

Thanks!
Miquèl

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 10/17] irqchip/irq-mvebu-sei: add new driver for Marvell SEI
@ 2018-05-18 13:22       ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-05-18 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

On Wed, 2 May 2018 11:17:44 +0200, Thomas Petazzoni
<thomas.petazzoni@bootlin.com> wrote:

> Hello,
> 
> On Sat, 21 Apr 2018 15:55:30 +0200, Miquel Raynal wrote:
> 
> > diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> > index 5ed465ab1c76..6b5b75cb4694 100644
> > --- a/drivers/irqchip/Makefile
> > +++ b/drivers/irqchip/Makefile
> > @@ -73,6 +73,7 @@ obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
> >  obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
> >  obj-$(CONFIG_MSCC_OCELOT_IRQ)		+= irq-mscc-ocelot.o
> >  obj-$(CONFIG_MVEBU_GICP)		+= irq-mvebu-gicp.o
> > +obj-$(CONFIG_MVEBU_SEI)			+= irq-mvebu-sei.o
> >  obj-$(CONFIG_MVEBU_ICU)			+= irq-mvebu-icu.o
> >  obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
> >  obj-$(CONFIG_MVEBU_PIC)			+= irq-mvebu-pic.o  
> 
> Alphabetic ordering would put SEI after PIC I guess :)

Sure.

> 
> > diff --git a/drivers/irqchip/irq-mvebu-sei.c b/drivers/irqchip/irq-mvebu-sei.c
> > new file mode 100644
> > index 000000000000..5c12c74e3f09
> > --- /dev/null
> > +++ b/drivers/irqchip/irq-mvebu-sei.c
> > @@ -0,0 +1,449 @@
> > +// SPDX-License-Identifier: GPL-2.0 OR X11  
> 
> License for code is GPL-2.0 only. We use GPL-2.0 OR X11 for Device
> Trees.

I did not know, thanks for the explanation.

> 
> > +#define pr_fmt(fmt) "mvebu-sei: " fmt
> > +
> > +#include <linux/irq.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/irqchip/chained_irq.h>
> > +#include <linux/irqdomain.h>
> > +#include <linux/kernel.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/msi.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/irqchip.h>
> > +
> > +#include <dt-bindings/interrupt-controller/arm-gic.h>
> > +
> > +#define GICP_SET_SEI_OFFSET	0x30
> > +#define GICP_CLR_SEI_OFFSET	GICP_SET_SEI_OFFSET  
> 
> Why do you have this concept of set/clr if there is only one register ?
> I assume that if there is only a "set" register, it means that SEI
> interrupts can only be edge triggered, contrary to NSR interrupts,
> which have separate set/clr to support level-triggered interrupts.
> 
> Having only a "set" offset means that we can rely on the existing
> "struct msi_msg" to convey both the MSI doorbell address and payload,
> and we don't need the mvebu_gicp_get_doorbells() hack.

I misunderstood the specification at first (when copying code from the
gicp driver), and then continued in my mistake. I removed the whole
doorbell thing.

> 
> > +/* Cause register */
> > +#define GICP_SECR(idx)		(0x0  + (idx * 0x4))
> > +/* Mask register */
> > +#define GICP_SEMR(idx)		(0x20 + (idx * 0x4))  
> 
> Minor nit: order register definitions by order of increasing offset,
> i.e the GICP_SET_SEI_OFFSET should be defined here.

Ok.

> 
> > +#define SEI_IRQ_NB_PER_REG	32
> > +#define SEI_IRQ_REG_NB		2  
> 
> s/NB/COUNT/

Changed.

> 
> > +#define SEI_IRQ_NB		(SEI_IRQ_NB_PER_REG * SEI_IRQ_REG_NB)  
> 
> Ditto.
> 
> > +#define SEI_IRQ_REG_IDX(irq_id)	(irq_id / SEI_IRQ_NB_PER_REG)
> > +#define SEI_IRQ_REG_BIT(irq_id)	(irq_id % SEI_IRQ_NB_PER_REG)
> > +
> > +struct mvebu_sei_interrupt_range {
> > +	u32 first;
> > +	u32 number;
> > +};
> > +
> > +struct mvebu_sei {
> > +	struct device *dev;
> > +	void __iomem *base;
> > +	struct resource *res;
> > +	struct irq_domain *ap_domain;
> > +	struct irq_domain *cp_domain;
> > +	struct mvebu_sei_interrupt_range ap_interrupts;
> > +	struct mvebu_sei_interrupt_range cp_interrupts;
> > +	/* Lock on MSI allocations/releases */
> > +	spinlock_t cp_msi_lock;
> > +	DECLARE_BITMAP(cp_msi_bitmap, SEI_IRQ_NB);
> > +};
> > +
> > +static int mvebu_sei_domain_to_sei_irq(struct mvebu_sei *sei,
> > +				       struct irq_domain *domain,
> > +				       irq_hw_number_t hwirq)
> > +{
> > +	if (domain == sei->ap_domain)
> > +		return sei->ap_interrupts.first + hwirq;
> > +	else
> > +		return sei->cp_interrupts.first + hwirq;  
> 
> I am not entirely clear whether we need subnodes or not in this
> binding, but I guess we do because we have one subset of the interrupts
> that are wired interrupts, and another part that are MSI triggered.
> 
> Perhaps this is one aspect on which Marc Zyngier can comment ?
> 
> > +static void mvebu_sei_reset(struct mvebu_sei *sei)
> > +{
> > +	u32 reg_idx;
> > +
> > +	for (reg_idx = 0; reg_idx < SEI_IRQ_REG_NB; reg_idx++) {
> > +		/* Clear all cause bits */
> > +		writel(0xFFFFFFFF, sei->base + GICP_SECR(reg_idx));
> > +		/* Enable all interrupts */
> > +		writel(0, sei->base + GICP_SEMR(reg_idx));  
> 
> Enabling interrupts by default ? This looks weird. They should only be
> enabled... when enabled.

That's right, no need to enable them here.

> 
> > +int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
> > +			    phys_addr_t *clr)
> > +{
> > +	struct platform_device *pdev;
> > +	struct mvebu_sei *sei;
> > +
> > +	pdev = of_find_device_by_node(dn->parent);
> > +	if (!pdev)
> > +		return -ENODEV;
> > +
> > +	sei = platform_get_drvdata(pdev);
> > +	if (!sei)
> > +		return -ENODEV;
> > +
> > +	*set = (phys_addr_t)(sei->res->start + GICP_SET_SEI_OFFSET);
> > +	*clr = (phys_addr_t)(sei->res->start + GICP_CLR_SEI_OFFSET);
> > +
> > +	return 0;
> > +}  
> 
> As I said above, I believe this hack is not needed, because SEIs are
> edge-triggered, and we have a single SET_SEI_OFFSET MSI doorbell
> address to convey, which makes "struct msi_msg" as it is today
> sufficient.

Removed.

> 
> > +static void mvebu_sei_mask_irq(struct irq_data *d)
> > +{
> > +	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
> > +	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);  
> 
> This doesn't look right. The d->hwirq is relative to the beginning of
> the domain, while you should use sei_irq here. For example, the SEI
> n?32 (first interrupt in the second register) will have d->hwirq = 11,
> because it is the 11th SEI interrupt for the CP. So here, you will
> conclude that reg_idx = 0, while it should be reg_idx = 1.

This is true. I did not saw it because... well... all interrupts were
enabled by default.

> 
> > +	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
> > +	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
> > +	u32 reg;
> > +
> > +	/* 1 disables the interrupt */
> > +	reg =  readl(sei->base + GICP_SEMR(reg_idx));
> > +	writel(reg | irq_mask, sei->base + GICP_SEMR(reg_idx));  
> 
> Personal taste here, but I prefer:
> 
> 	reg =  readl(sei->base + GICP_SEMR(reg_idx));
> 	reg |= BIT(SEI_IRQ_REG_BIT(sei_irq));
> 	writel(reg, sei->base + GICP_SEMR(reg_idx));

No problem.

> 
> > +static void mvebu_sei_unmask_irq(struct irq_data *d)
> > +{
> > +	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
> > +	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);  
> 
> Same mistake as above I believe.
> 
> > +	u32 sei_irq = mvebu_sei_domain_to_sei_irq(sei, d->domain, d->hwirq);
> > +	u32 irq_mask = BIT(SEI_IRQ_REG_BIT(sei_irq));
> > +	u32 reg;
> > +
> > +	/* 0 enables the interrupt */
> > +	reg = readl(sei->base + GICP_SEMR(reg_idx));
> > +	writel(reg & ~irq_mask, sei->base + GICP_SEMR(reg_idx));  
> 
> And same nitpick comment :-)
> 
> > +static int mvebu_sei_irq_domain_alloc(struct irq_domain *domain,
> > +				      unsigned int virq, unsigned int nr_irqs,
> > +				      void *args)  
> 
> I think the coding style says that arguments should be aligned, no ?
> 
> > +{
> > +	struct mvebu_sei *sei = domain->host_data;
> > +	struct irq_fwspec *fwspec = args;
> > +	struct irq_chip *irq_chip;
> > +	int sei_hwirq, hwirq;
> > +	int ret;
> > +
> > +	/* Software only supports single allocations for now */
> > +	if (nr_irqs != 1)
> > +		return -ENOTSUPP;
> > +
> > +	if (domain == sei->ap_domain) {
> > +		irq_chip = &mvebu_sei_ap_wired_irq_chip;
> > +		hwirq = fwspec->param[0];
> > +	} else {
> > +		irq_chip = &mvebu_sei_cp_msi_irq_chip;
> > +		spin_lock(&sei->cp_msi_lock);
> > +		hwirq = bitmap_find_free_region(sei->cp_msi_bitmap, SEI_IRQ_NB,
> > +						0);
> > +		spin_unlock(&sei->cp_msi_lock);
> > +		if (hwirq < 0)
> > +			return -ENOSPC;
> > +	}
> > +
> > +	sei_hwirq = mvebu_sei_domain_to_sei_irq(sei, domain, hwirq);
> > +
> > +	fwspec->fwnode = domain->parent->fwnode;
> > +	fwspec->param_count = 3;
> > +	fwspec->param[0] = GIC_SPI;
> > +	fwspec->param[1] = sei_hwirq;
> > +	fwspec->param[2] = IRQ_TYPE_EDGE_RISING;  
> 
> Maybe it's me being confused, but I thought all SEI interrupts were
> muxed together to a single SPI for the parent GIC. But here, you
> allocate different SPIs at the GIC level. Intuitively, this doesn't
> look good. Haven't you copy/pasted too much from the gicp driver, where
> we have a 1:1 mapping between interrupts coming into the GICP and
> interrupts signaled by the GICP to the GIC, while here we have a N:1
> mapping, with N interrupts coming into the GICP_SEI, and only one
> interrupt leaving the GICP_SEI to the GIC ?

I am a bit in troubles understanding what fwspec->param[1] exactly
means here. I suppose I should s/sei_hwirq/0/ as there is only one SPI
interrupt to refer to?

Maybe Marc can comment on this too?

> 
> > +static const struct irq_domain_ops mvebu_sei_ap_domain_ops = {
> > +	.xlate = irq_domain_xlate_onecell,
> > +	.alloc = mvebu_sei_irq_domain_alloc,
> > +	.free = mvebu_sei_irq_domain_free,
> > +};
> > +
> > +static const struct irq_domain_ops mvebu_sei_cp_domain_ops = {
> > +	.xlate = irq_domain_xlate_twocell,
> > +	.alloc = mvebu_sei_irq_domain_alloc,
> > +	.free = mvebu_sei_irq_domain_free,
> > +};  
> 
> Why do you need two cells for the interrupts coming from the CP and
> only one cell for the interrupts coming from the AP ?
> 
> For thermal in the AP, you do:
> 
> +					interrupt-parent = <&sei_wired_controller>;
> +					interrupts = <18>;
> 
> i.e, you don't specify an interrupt type. For thermal in the CP, you do:
> 
> +				interrupts-extended =
> +					<&CP110_LABEL(icu_sei) 116 IRQ_TYPE_LEVEL_HIGH>;
> 
> here you specify an interrupt type. I'm not sure why you have this
> difference. Even more so because I think a SEI level interrupt is not
> possible, since you only have a "SET" register and no "CLR" register.

and then you wrote:

<quote>
> OK, my comment is not very correct here, I'm comparing apple to
> oranges. The former its an interrupt directly pointing to the GICP_SEI,
> while the latter is an interrupt of the ICU, which itself will notify
> the GICP_SEI through an MSI.

> However, I'm still confused as to why you have .xlate =
> irq_domain_xlate_twocell for the mvebu_sei_cp_domain_ops. I think there
> is no need for ->xlate() call back here because it's going to be a MSI
> domain.
</quote>

For thermal in the AP I should probably add an IRQ_TYPE_LEVEL_HIGH in
order to describe properly the interrupt (wired).

I also removed the .xlate entry for the CP domain, I was not sure it
was useless for MSI but it looks it is.

> 
> Some guidance from Marc here might be useful perhaps.
> 
> 
> > +static int mvebu_sei_probe(struct platform_device *pdev)
> > +{
> > +	struct device_node *node = pdev->dev.of_node, *parent, *child;
> > +	struct irq_domain *parent_domain, *plat_domain;
> > +	struct mvebu_sei *sei;
> > +	const __be32 *property;
> > +	u32 top_level_spi, size;
> > +	int ret;
> > +
> > +	sei = devm_kzalloc(&pdev->dev, sizeof(*sei), GFP_KERNEL);
> > +	if (!sei)
> > +		return -ENOMEM;
> > +
> > +	sei->dev = &pdev->dev;
> > +
> > +	spin_lock_init(&sei->cp_msi_lock);
> > +
> > +	sei->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	if (!sei->res) {
> > +		dev_err(sei->dev, "Failed to retrieve SEI resource\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	sei->base = devm_ioremap(sei->dev, sei->res->start,
> > +				 resource_size(sei->res));
> > +	if (!sei->base) {
> > +		dev_err(sei->dev, "Failed to remap SEI resource\n");
> > +		return -ENODEV;
> > +	}  
> 
> Use devm_ioremap_resource() here, and remove the error handling of
> platform_get_resource(), because it's already taken care of by
> devm_ioremap_resource().

Good tip, I'll remember.

> 
> > +	/*
> > +	 * Reserve the single (top-level) parent SPI IRQ from which all the
> > +	 * interrupts handled by this driver will be signaled.
> > +	 */
> > +	top_level_spi = irq_of_parse_and_map(node, 0);
> > +	if (top_level_spi <= 0) {
> > +		dev_err(sei->dev, "Failed to retrieve top-level SPI IRQ\n");
> > +		return -ENODEV;
> > +	}  
> 
> Rather than top_level_spi, something like parent_irq would make more
> sense to me.

Renamed.

> 
> > +	irq_set_chained_handler(top_level_spi, mvebu_sei_handle_cascade_irq);
> > +	irq_set_handler_data(top_level_spi, sei);
> > +
> > +	/*
> > +	 * SEIs in the range [ 0; 20] are wired and come from the AP.
> > +	 * SEIs in the range [21; 63] are CP SEI and are triggered through MSIs.
> > +	 *
> > +	 * Each SEI 'domain' is represented as a subnode.
> > +	 */
> > +
> > +	/* Get a reference to the parent domain to create a hierarchy */
> > +	parent = of_irq_find_parent(node);
> > +	if (!parent) {
> > +		dev_err(sei->dev, "Failed to find parent IRQ node\n");
> > +		ret = -ENODEV;
> > +		goto dispose_irq;
> > +	}
> > +
> > +	parent_domain = irq_find_host(parent);
> > +	if (!parent_domain) {
> > +		dev_err(sei->dev, "Failed to find parent IRQ domain\n");
> > +		ret = -ENODEV;
> > +		goto dispose_irq;
> > +	}
> > +
> > +	/* Create the 'wired' hierarchy */
> > +	child = of_find_node_by_name(node, "sei-wired-controller");
> > +	if (!child) {
> > +		dev_err(sei->dev, "Missing 'sei-wired-controller' subnode\n");
> > +		ret = -ENODEV;
> > +		goto dispose_irq;
> > +	}  
> 
> Don't forget to of_node_put(child) once you're done using this DT node
> reference.

Ok.

> 
> > +
> > +	property = of_get_property(child, "reg", &size);
> > +	if (!property || size != (2 * sizeof(u32))) {
> > +		dev_err(sei->dev, "Missing subnode 'reg' property\n");
> > +		ret = -ENODEV;
> > +		goto dispose_irq;
> > +	}  
> 
> As Rob said, I don't think the "reg" property is appropriate for this
> usage.

I will change.

> 
> > +	sei->ap_interrupts.first = be32_to_cpu(property[0]);
> > +	sei->ap_interrupts.number = be32_to_cpu(property[1]);
> > +	sei->ap_domain = irq_domain_create_hierarchy(parent_domain, 0,
> > +						     sei->ap_interrupts.number,
> > +						     of_node_to_fwnode(child),
> > +						     &mvebu_sei_ap_domain_ops,
> > +						     sei);
> > +	if (!sei->ap_domain) {
> > +		dev_err(sei->dev, "Failed to create AP IRQ domain\n");
> > +		ret = -ENOMEM;
> > +		goto dispose_irq;
> > +	}
> > +
> > +	/* Create the 'MSI' hierarchy */
> > +	child = of_find_node_by_name(node, "sei-msi-controller");
> > +	if (!child) {
> > +		dev_err(sei->dev, "Missing 'sei-msi-controller' subnode\n");
> > +		ret = -ENODEV;
> > +		goto remove_ap_domain;
> > +	}  
> 
> Ditto: missing of_node_put(child) somewhere below to balance
> of_find_node_by_name().

Ok.

> 
> > +	property = of_get_property(child, "reg", &size);
> > +	if (!property || size != (2 * sizeof(u32))) {
> > +		dev_err(sei->dev, "Missing subnode 'reg' property\n");
> > +		ret = -ENODEV;
> > +		goto remove_ap_domain;
> > +	}
> > +
> > +	sei->cp_interrupts.first = be32_to_cpu(property[0]);
> > +	sei->cp_interrupts.number = be32_to_cpu(property[1]);
> > +	sei->cp_domain = irq_domain_create_hierarchy(parent_domain, 0,
> > +						     sei->cp_interrupts.number,
> > +						     of_node_to_fwnode(child),
> > +						     &mvebu_sei_cp_domain_ops,
> > +						     sei);
> > +	if (!sei->cp_domain) {
> > +		pr_err("Failed to create CPs IRQ domain\n");
> > +		ret = -ENOMEM;
> > +		goto remove_ap_domain;
> > +	}
> > +
> > +	plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(child),
> > +						     &mvebu_sei_msi_domain_info,
> > +						     sei->cp_domain);
> > +	if (!plat_domain) {
> > +		pr_err("Failed to create CPs MSI domain\n");
> > +		ret = -ENOMEM;
> > +		goto remove_cp_domain;
> > +	}  
> 
> 
> 
> > +
> > +	platform_set_drvdata(pdev, sei);
> > +
> > +	mvebu_sei_reset(sei);  
> 
> Please do the reset *before* registering the IRQ domains, it's more
> logical to have the HW ready and then expose it to Linux rather than
> the opposite.

Sure.

> 
> It would be nice to have the review from Marc on this driver,
> especially on whether the SEI is properly modeled in terms of IRQ
> domains;
> 
> > diff --git a/drivers/irqchip/irq-mvebu-sei.h b/drivers/irqchip/irq-mvebu-sei.h
> > new file mode 100644
> > index 000000000000..f0c12a441923
> > --- /dev/null
> > +++ b/drivers/irqchip/irq-mvebu-sei.h
> > @@ -0,0 +1,12 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef __MVEBU_SEI_H__
> > +#define __MVEBU_SEI_H__
> > +
> > +#include <linux/types.h>
> > +
> > +struct device_node;
> > +
> > +int mvebu_sei_get_doorbells(struct device_node *dn, phys_addr_t *set,
> > +			    phys_addr_t *clr);
> > +
> > +#endif /* __MVEBU_SEI_H__ */  
> 
> This header file can be removed if you drop mvebu_sei_get_doorbells(),
> as suggested above.

Indeed.

> 
> Best regards,
> 
> Thomas

Thanks!
Miqu?l

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

* Re: [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
  2018-04-30 14:09         ` Rob Herring
@ 2018-05-18 14:48           ` Miquel Raynal
  -1 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-05-18 14:48 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Rutland, Andrew Lunn, Jason Cooper, devicetree,
	Marc Zyngier, Catalin Marinas, Gregory Clement, Haim Boot,
	Will Deacon, Maxime Chevallier, Nadav Haklai, Antoine Tenart,
	Thomas Petazzoni, Thomas Gleixner, Hanna Hawa,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Sebastian Hesselbarth

Hi Rob,

On Mon, 30 Apr 2018 09:09:10 -0500, Rob Herring <robh@kernel.org> wrote:

> On Sat, Apr 28, 2018 at 5:48 AM, Miquel Raynal
> <miquel.raynal@bootlin.com> wrote:
> > Hi Rob,
> >
> > On Fri, 27 Apr 2018 15:50:32 -0500, Rob Herring <robh@kernel.org> wrote:
> >  
> >> On Sat, Apr 21, 2018 at 03:55:34PM +0200, Miquel Raynal wrote:  
> >> > Describe the SEI (System Error Interrupt) controller driver. The
> >> > controller is part of the GIC. It aggregates two types of interrupts,
> >> > wired and MSIs from respectively the AP and the CPs, into a single SPI
> >> > interrupt.
> >> >
> >> > Suggested-by: Haim Boot <hayim@marvell.com>
> >> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> >> > ---
> >> >  .../bindings/interrupt-controller/marvell,sei.txt  | 54 ++++++++++++++++++++++
> >> >  1 file changed, 54 insertions(+)
> >> >  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> >> >
> >> > diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> >> > new file mode 100644
> >> > index 000000000000..a246d59552b1
> >> > --- /dev/null
> >> > +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> >> > @@ -0,0 +1,54 @@
> >> > +Marvell SEI (System Error Interrupt) Controller
> >> > +-----------------------------------------------
> >> > +
> >> > +Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
> >> > +It receives interrupts from several sources and aggregates them to a single
> >> > +interrupt line (an SPI) on the primary interrupt controller.
> >> > +
> >> > +The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is
> >> > +wired while a second set comes from the CPs by the mean of MSIs. Each
> >> > +'domain' is represented as a subnode.
> >> > +
> >> > +Required properties:
> >> > +
> >> > +- compatible: should be "marvell,armada-8k-sei".
> >> > +- reg: SEI registers location and length.
> >> > +- interrupts: identifies the parent IRQ that will be triggered.
> >> > +- #address-cells: should be '1', represents the position of the first
> >> > +                  IRQ of a given type in the SEI range.
> >> > +- #size-cells: should be '1', represents the number of a given type of
> >> > +               IRQs.
> >> > +
> >> > +Child node 'sei-wired-controller' required properties:
> >> > +
> >> > +- reg: the range of wired interrupts.
> >> > +- #interrupt-cells: number of cells to define an SEI wired interrupt
> >> > +                    coming from the AP, should be 1. The cell is the IRQ
> >> > +                    number.
> >> > +- interrupt-controller: identifies the node as an interrupt controller.
> >> > +
> >> > +Child node 'sei-msi-controller' required properties:
> >> > +
> >> > +- reg: the range of non-wired interrupts triggered by way of MSIs.
> >> > +- msi-controller: identifies the node as an MSI controller.
> >> > +
> >> > +Example:
> >> > +
> >> > +        sei: sei@3f0200 {
> >> > +               compatible = "marvell,armada-8k-sei";
> >> > +               reg = <0x3f0200 0x40>;
> >> > +               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
> >> > +               #address-cells = <1>;
> >> > +               #size-cells = <1>;
> >> > +
> >> > +               sei_wired_controller: sei-wired-controller@0 {
> >> > +                       reg = <0 21>;  
> >>
> >> Using interrupt numbers in reg is strange.  
> >
> > I thought the reg property was the one to choose here, I can of course
> > change it, what would you suggest?
> >  
> >>  
> >> > +                       #interrupt-cells = <1>;
> >> > +                       interrupt-controller;
> >> > +               };
> >> > +
> >> > +               sei_msi_controller: sei-msi-controller@21 {
> >> > +                       reg = <21 43>;
> >> > +                       msi-controller;  
> >>
> >> Can't the parent be both an interrupt-controller and msi-controller?  

I would prefer to describe how the hardware is split in two
sub-controllers. And to answer the question: no, the parent cannot be
both and interrupt-controller and an msi-controller.

> >
> > We need to know which one aggregates interrupts, which one receives
> > MSIs and most importantly which interrupt is what (within the 64
> > that are handled by the SEI).  
> 
> You mean that 0-20 are wired and 21-63 are msi? "marvell,msi-base =
> <21>;" in the parent would be sufficient for that though you may want
> something more flexible to have multiple ranges.

Absolutely, I would like something more flexible.

> 
> It looks like there may already be similar bindings. See
> 'msi-available-ranges" and "{al,arm},msi-base-spi".

If you are ok, I will use a new property named 'marvell,sei-ranges'
instead of the reg property which is indeed more explicit.

Thanks,
Miquèl

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node
@ 2018-05-18 14:48           ` Miquel Raynal
  0 siblings, 0 replies; 92+ messages in thread
From: Miquel Raynal @ 2018-05-18 14:48 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Rob,

On Mon, 30 Apr 2018 09:09:10 -0500, Rob Herring <robh@kernel.org> wrote:

> On Sat, Apr 28, 2018 at 5:48 AM, Miquel Raynal
> <miquel.raynal@bootlin.com> wrote:
> > Hi Rob,
> >
> > On Fri, 27 Apr 2018 15:50:32 -0500, Rob Herring <robh@kernel.org> wrote:
> >  
> >> On Sat, Apr 21, 2018 at 03:55:34PM +0200, Miquel Raynal wrote:  
> >> > Describe the SEI (System Error Interrupt) controller driver. The
> >> > controller is part of the GIC. It aggregates two types of interrupts,
> >> > wired and MSIs from respectively the AP and the CPs, into a single SPI
> >> > interrupt.
> >> >
> >> > Suggested-by: Haim Boot <hayim@marvell.com>
> >> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> >> > ---
> >> >  .../bindings/interrupt-controller/marvell,sei.txt  | 54 ++++++++++++++++++++++
> >> >  1 file changed, 54 insertions(+)
> >> >  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> >> >
> >> > diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> >> > new file mode 100644
> >> > index 000000000000..a246d59552b1
> >> > --- /dev/null
> >> > +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt
> >> > @@ -0,0 +1,54 @@
> >> > +Marvell SEI (System Error Interrupt) Controller
> >> > +-----------------------------------------------
> >> > +
> >> > +Marvell SEI (System Error Interrupt) controller is an interrupt aggregator.
> >> > +It receives interrupts from several sources and aggregates them to a single
> >> > +interrupt line (an SPI) on the primary interrupt controller.
> >> > +
> >> > +The IRQ chip can handle up to 64 SEIs, a set comes from the AP and is
> >> > +wired while a second set comes from the CPs by the mean of MSIs. Each
> >> > +'domain' is represented as a subnode.
> >> > +
> >> > +Required properties:
> >> > +
> >> > +- compatible: should be "marvell,armada-8k-sei".
> >> > +- reg: SEI registers location and length.
> >> > +- interrupts: identifies the parent IRQ that will be triggered.
> >> > +- #address-cells: should be '1', represents the position of the first
> >> > +                  IRQ of a given type in the SEI range.
> >> > +- #size-cells: should be '1', represents the number of a given type of
> >> > +               IRQs.
> >> > +
> >> > +Child node 'sei-wired-controller' required properties:
> >> > +
> >> > +- reg: the range of wired interrupts.
> >> > +- #interrupt-cells: number of cells to define an SEI wired interrupt
> >> > +                    coming from the AP, should be 1. The cell is the IRQ
> >> > +                    number.
> >> > +- interrupt-controller: identifies the node as an interrupt controller.
> >> > +
> >> > +Child node 'sei-msi-controller' required properties:
> >> > +
> >> > +- reg: the range of non-wired interrupts triggered by way of MSIs.
> >> > +- msi-controller: identifies the node as an MSI controller.
> >> > +
> >> > +Example:
> >> > +
> >> > +        sei: sei at 3f0200 {
> >> > +               compatible = "marvell,armada-8k-sei";
> >> > +               reg = <0x3f0200 0x40>;
> >> > +               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
> >> > +               #address-cells = <1>;
> >> > +               #size-cells = <1>;
> >> > +
> >> > +               sei_wired_controller: sei-wired-controller at 0 {
> >> > +                       reg = <0 21>;  
> >>
> >> Using interrupt numbers in reg is strange.  
> >
> > I thought the reg property was the one to choose here, I can of course
> > change it, what would you suggest?
> >  
> >>  
> >> > +                       #interrupt-cells = <1>;
> >> > +                       interrupt-controller;
> >> > +               };
> >> > +
> >> > +               sei_msi_controller: sei-msi-controller at 21 {
> >> > +                       reg = <21 43>;
> >> > +                       msi-controller;  
> >>
> >> Can't the parent be both an interrupt-controller and msi-controller?  

I would prefer to describe how the hardware is split in two
sub-controllers. And to answer the question: no, the parent cannot be
both and interrupt-controller and an msi-controller.

> >
> > We need to know which one aggregates interrupts, which one receives
> > MSIs and most importantly which interrupt is what (within the 64
> > that are handled by the SEI).  
> 
> You mean that 0-20 are wired and 21-63 are msi? "marvell,msi-base =
> <21>;" in the parent would be sufficient for that though you may want
> something more flexible to have multiple ranges.

Absolutely, I would like something more flexible.

> 
> It looks like there may already be similar bindings. See
> 'msi-available-ranges" and "{al,arm},msi-base-spi".

If you are ok, I will use a new property named 'marvell,sei-ranges'
instead of the reg property which is indeed more explicit.

Thanks,
Miqu?l

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

end of thread, other threads:[~2018-05-18 14:48 UTC | newest]

Thread overview: 92+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-21 13:55 [PATCH 00/17] Add System Error Interrupt support to Armada SoCs Miquel Raynal
2018-04-21 13:55 ` Miquel Raynal
2018-04-21 13:55 ` [PATCH 01/17] dt-bindings/interrupt-controller: fix Marvell ICU length in the example Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-27 20:16   ` Rob Herring
2018-04-27 20:16     ` Rob Herring
2018-04-30 13:44   ` Thomas Petazzoni
2018-04-30 13:44     ` Thomas Petazzoni
2018-04-21 13:55 ` [PATCH 02/17] arm64: dts: marvell: fix CP110 ICU node size Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-30 12:38   ` Gregory CLEMENT
2018-04-30 12:38     ` Gregory CLEMENT
2018-04-30 13:44   ` Thomas Petazzoni
2018-04-30 13:44     ` Thomas Petazzoni
2018-04-21 13:55 ` [PATCH 03/17] arm64: dts: marvell: add syscon compatible to CP110 ICU node Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-30 13:45   ` Thomas Petazzoni
2018-04-30 13:45     ` Thomas Petazzoni
2018-04-21 13:55 ` [PATCH 04/17] irqchip/irq-mvebu-icu: fix wrong user data retrieval Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-30 13:49   ` Thomas Petazzoni
2018-04-30 13:49     ` Thomas Petazzoni
2018-05-03 14:57     ` Miquel Raynal
2018-05-03 14:57       ` Miquel Raynal
2018-04-21 13:55 ` [PATCH 05/17] irqchip/irq-mvebu-icu: clarify the reset operation of configured interrupts Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-30 13:51   ` Thomas Petazzoni
2018-04-30 13:51     ` Thomas Petazzoni
2018-04-21 13:55 ` [PATCH 06/17] irqchip/irq-mvebu-icu: switch to regmap Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-30 12:42   ` Gregory CLEMENT
2018-04-30 12:42     ` Gregory CLEMENT
2018-04-30 13:53   ` Thomas Petazzoni
2018-04-30 13:53     ` Thomas Petazzoni
2018-05-03 15:05     ` Miquel Raynal
2018-05-03 15:05       ` Miquel Raynal
2018-04-30 13:58   ` Thomas Petazzoni
2018-04-30 13:58     ` Thomas Petazzoni
2018-04-21 13:55 ` [PATCH 07/17] irqchip/irq-mvebu-icu: make irq_domain local Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-05-02  8:02   ` Thomas Petazzoni
2018-05-02  8:02     ` Thomas Petazzoni
2018-04-21 13:55 ` [PATCH 08/17] irqchip/irq-mvebu-icu: disociate ICU and NSR Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-05-02  8:03   ` Thomas Petazzoni
2018-05-02  8:03     ` Thomas Petazzoni
2018-04-21 13:55 ` [PATCH 09/17] irqchip/irq-mvebu-icu: support ICU subnodes Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-05-02  8:13   ` Thomas Petazzoni
2018-05-02  8:13     ` Thomas Petazzoni
2018-05-04  8:32     ` Miquel Raynal
2018-05-04  8:32       ` Miquel Raynal
2018-04-21 13:55 ` [PATCH 10/17] irqchip/irq-mvebu-sei: add new driver for Marvell SEI Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-05-02  9:17   ` Thomas Petazzoni
2018-05-02  9:17     ` Thomas Petazzoni
2018-05-02 15:56     ` Thomas Petazzoni
2018-05-02 15:56       ` Thomas Petazzoni
2018-05-18 13:22     ` Miquel Raynal
2018-05-18 13:22       ` Miquel Raynal
2018-04-21 13:55 ` [PATCH 11/17] arm64: marvell: enable SEI driver Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-30 13:01   ` Gregory CLEMENT
2018-04-30 13:01     ` Gregory CLEMENT
2018-04-21 13:55 ` [PATCH 12/17] irqchip/irq-mvebu-icu: add support for System Error Interrupts (SEI) Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-21 13:55 ` [PATCH 13/17] dt-bindings/interrupt-controller: update Marvell ICU bindings Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-27 20:47   ` Rob Herring
2018-04-27 20:47     ` Rob Herring
2018-04-28 10:42     ` Miquel Raynal
2018-04-28 10:42       ` Miquel Raynal
2018-04-28 10:50       ` Thomas Petazzoni
2018-04-28 10:50         ` Thomas Petazzoni
2018-04-21 13:55 ` [PATCH 14/17] dt-bindings/interrupt-controller: add description for Marvell SEI node Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-27 20:50   ` Rob Herring
2018-04-27 20:50     ` Rob Herring
2018-04-28 10:48     ` Miquel Raynal
2018-04-28 10:48       ` Miquel Raynal
2018-04-30 14:09       ` Rob Herring
2018-04-30 14:09         ` Rob Herring
2018-05-18 14:48         ` Miquel Raynal
2018-05-18 14:48           ` Miquel Raynal
2018-04-30 14:24   ` Thomas Petazzoni
2018-04-30 14:24     ` Thomas Petazzoni
2018-04-21 13:55 ` [PATCH 15/17] arm64: dts: marvell: add AP806 SEI subnode Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-21 13:55 ` [PATCH 16/17] arm64: dts: marvell: use new bindings for CP110 interrupts Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal
2018-04-21 13:55 ` [PATCH 17/17] arm64: dts: marvell: add CP110 ICU SEI subnode Miquel Raynal
2018-04-21 13:55   ` Miquel Raynal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.