irqchip: Add Sophgo SG2042 MSI controller
v3 cover irqchip: Add Sophgo SG2042 MSI controller
From: Chen Wang <[email protected]>
This controller is on the Sophgo SG2042 SoC to transform interrupts from PCIe MSI to PLIC interrupts.
Thanks,
Chen
---
Changes in v3:
The patch series is based on v6.13-rc7.
Fixed following issues as per comments from Krzysztof Kozlowski, Samuel Holland, Christophe JAILLET, Inochi Amaoto, thanks.
- bindings: use reg for doorbell, fixed wrong usage of additionalProperties and misc.
- Improve driver code:
- Fixed potentional memory leak issues.
- Fixed some build warnings reported by test robot.
- Optimize and simplify the code when allocating hwirq.
- Use DECLARE_BITMAP instead of kzalloc.
- Some other coding style improvements.
Changes in v2:
The patch series is based on v6.13-rc2. You can simply review or test the patches at the link [2].
Fixed following issues as per comments from Rob Herring, Thomas Gleixner, thanks.
- Improve driver binding description, use msi-ranges instread.
- Improve driver code:
- Improve coding style.
- Fixed bug that possible memory leak of bitmap when sg2042_msi_init_domains returns error.
- Use guard(mutex).
- Use the MSI parent model.
Changes in v1:
The patch series is based on v6.12-rc7. You can simply review or test the patches at the link [1].
---
Chen Wang (3):
dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
irqchip: Add the Sophgo SG2042 MSI interrupt controller
riscv: sophgo: dts: add msi controller for SG2042
.../sophgo,sg2042-msi.yaml | 58 ++++ arch/riscv/boot/dts/sophgo/sg2042.dtsi | 10 + drivers/irqchip/Kconfig | 12 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-sg2042-msi.c | 268 ++++++++++++++++++ 5 files changed, 349 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml create mode 100644 drivers/irqchip/irq-sg2042-msi.c
base-commit: 5bc55a333a2f7316b58edc7573e8e893f7acb532
Signature · 1 line
2.34.1
PATCH v3 1/3 dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
From: Chen Wang <[email protected]>
Add binding for Sophgo SG2042 MSI controller.
--- .../sophgo,sg2042-msi.yaml | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +58 -0
@@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/sophgo,sg2042-msi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sophgo SG2042 MSI Controller + +maintainers: + - Chen Wang <[email protected]> + +description: + This interrupt controller is in Sophgo SG2042 for transforming interrupts from + PCIe MSI to PLIC interrupts. + +allOf: + - $ref: /schemas/interrupts.yaml# + - $ref: /schemas/interrupt-controller/msi-controller.yaml# + +properties: + compatible: + const: sophgo,sg2042-msi + + reg: + items: + - description: msi doorbell address + - description: clear register + + reg-names: + items: + - const: doorbell + - const: clr + + msi-controller: true + + msi-ranges: + maxItems: 1 + +required: + - compatible + - reg + - reg-names + - msi-controller + - msi-ranges + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + msi-controller@30000000 { + compatible = "sophgo,sg2042-msi"; + reg = <0x30000000 0x4>, <0x30000008 0x4>; + reg-names = "doorbell", "clr"; + msi-controller; + msi-ranges = <&plic 64 IRQ_TYPE_LEVEL_HIGH 32>; + interrupt-parent = <&plic>; + };
Signature · 1 line
2.34.1
Inochi Amaoto
maintainerRe: [PATCH v3 1/3] dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
Quoted 39 lines · Chen Wang
From: Chen Wang <[email protected]>
Add binding for Sophgo SG2042 MSI controller.
Signed-off-by Chen Wang <[email protected]>--- .../sophgo,sg2042-msi.yaml | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yamlDocumentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +23
-0@@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/sophgo,sg2042-msi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sophgo SG2042 MSI Controller + +maintainers: + - Chen Wang <[email protected]> + +description: + This interrupt controller is in Sophgo SG2042 for transforming interrupts from + PCIe MSI to PLIC interrupts. + +allOf: + - $ref: /schemas/interrupts.yaml# + - $ref: /schemas/interrupt-controller/msi-controller.yaml# + +properties: + compatible: + const: sophgo,sg2042-msi +
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 32
Quoted 10 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +9
-0+ reg: + items: + - description: msi doorbell address + - description: clear register + + reg-names: + items: + - const: doorbell + - const: clr
please reverse the items order, the clr addr is more suitable as the MMIO device address when writing device node. doorbeel address is just a IO address and can not be seen from CPU.
Quoted 34 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +26
-0+ + msi-controller: true + + msi-ranges: + maxItems: 1 + +required: + - compatible + - reg + - reg-names + - msi-controller + - msi-ranges + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + msi-controller@30000000 { + compatible = "sophgo,sg2042-msi"; + reg = <0x30000000 0x4>, <0x30000008 0x4>; + reg-names = "doorbell", "clr"; + msi-controller; + msi-ranges = <&plic 64 IRQ_TYPE_LEVEL_HIGH 32>; + interrupt-parent = <&plic>; + };Signature · 7 lines
2.34.1 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
Re: [PATCH v3 1/3] dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
Quoted 1 line · Inochi Amaoto
On Wed, Jan 15, 2025 at 02:33:23PM +0800, Chen Wang wrote:
[......]
Quoted 9 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 32
Quoted 9 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +9
-0+ reg: + items: + - description: msi doorbell address + - description: clear register + + reg-names: + items: + - const: doorbell + - const: clr
Quoted 3 lines
please reverse the items order, the clr addr is more suitable as the MMIO device address when writing device node. doorbeel address is just a IO address and can not be seen from CPU.
I find dtbcheck will report error if order is switched.
On SG2042, address of doorbell is ahead of clr.
Quoted 34 lines
Quoted 34 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +26
-0+ + msi-controller: true + + msi-ranges: + maxItems: 1 + +required: + - compatible + - reg + - reg-names + - msi-controller + - msi-ranges + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + msi-controller@30000000 { + compatible = "sophgo,sg2042-msi"; + reg = <0x30000000 0x4>, <0x30000008 0x4>; + reg-names = "doorbell", "clr"; + msi-controller; + msi-ranges = <&plic 64 IRQ_TYPE_LEVEL_HIGH 32>; + interrupt-parent = <&plic>; + };Signature · 7 lines
2.34.1 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
Inochi Amaoto
maintainerRe: [PATCH v3 1/3] dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
Quoted 13 lines · Chen Wang
Quoted 1 line · Inochi Amaoto
On Wed, Jan 15, 2025 at 02:33:23PM +0800, Chen Wang wrote:
[......]
Quoted 9 lines
Quoted 9 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +9
-0+ reg: + items: + - description: msi doorbell address + - description: clear register + + reg-names: + items: + - const: doorbell + - const: clr
Quoted 6 lines
Quoted 3 lines
please reverse the items order, the clr addr is more suitable as the MMIO device address when writing device node. doorbeel address is just a IO address and can not be seen from CPU.
I find dtbcheck will report error if order is switched.
You should also change the unit address to avoid error. I think you forgot it.
Quoted 2 lines
On SG2042, address of doorbell is ahead of clr.
It is the same on SG2044, but there is a problem that the doorbell addr is a IO address and it is not suitable to represent the device addr in the dtb. It also lead to a weird unit address on SG2044 which is hard to understand.
Regards,
Inochi
Re: [PATCH v3 1/3] dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
Quoted 13 lines · Inochi Amaoto
Quoted 12 lines · Chen Wang
Quoted 1 line · Inochi Amaoto
On Wed, Jan 15, 2025 at 02:33:23PM +0800, Chen Wang wrote:
[......]
Quoted 9 lines
Quoted 9 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +9
-0+ reg: + items: + - description: msi doorbell address + - description: clear register + + reg-names: + items: + - const: doorbell + - const: clr
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
please reverse the items order, the clr addr is more suitable as the MMIO device address when writing device node. doorbeel address is just a IO address and can not be seen from CPU.
I find dtbcheck will report error if order is switched.
You should also change the unit address to avoid error. I think you forgot it.
I forgot it, thanks for your suggestion.
Quoted 9 lines
Quoted 2 lines
On SG2042, address of doorbell is ahead of clr.
It is the same on SG2044, but there is a problem that the doorbell addr is a IO address and it is not suitable to represent the device addr in the dtb. It also lead to a weird unit address on SG2044 which is hard to understand.
Regards,
Inochi
Rob Herring
maintainerRe: [PATCH v3 1/3] dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
In reply to Chen WangQuoted 23 lines · Chen Wang
From: Chen Wang <[email protected]>
Add binding for Sophgo SG2042 MSI controller.
Signed-off-by Chen Wang <[email protected]>--- .../sophgo,sg2042-msi.yaml | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yamlDocumentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +7
-0@@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/sophgo,sg2042-msi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sophgo SG2042 MSI Controller
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 17
Quoted 10 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +10
-0+ +maintainers: + - Chen Wang <[email protected]> + +description: + This interrupt controller is in Sophgo SG2042 for transforming interrupts from + PCIe MSI to PLIC interrupts. + +allOf: + - $ref: /schemas/interrupts.yaml#
Drop this.
Quoted 10 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +10
-0+ - $ref: /schemas/interrupt-controller/msi-controller.yaml# + +properties: + compatible: + const: sophgo,sg2042-msi + + reg: + items: + - description: msi doorbell address + - description: clear register
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 37
Quoted 10 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +10
-0+ + reg-names: + items: + - const: doorbell + - const: clr + + msi-controller: true + + msi-ranges: + maxItems: 1
You need #msi-cells.
Quoted 24 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +21
-0+ +required: + - compatible + - reg + - reg-names + - msi-controller + - msi-ranges + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + msi-controller@30000000 { + compatible = "sophgo,sg2042-msi"; + reg = <0x30000000 0x4>, <0x30000008 0x4>; + reg-names = "doorbell", "clr"; + msi-controller; + msi-ranges = <&plic 64 IRQ_TYPE_LEVEL_HIGH 32>; + interrupt-parent = <&plic>; + };Signature · 1 line
2.34.1
Re: [PATCH v3 1/3] dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
hello, Rob,
Quoted 27 lines · Rob Herring
Quoted 26 lines · Chen Wang
From: Chen Wang <[email protected]>
Add binding for Sophgo SG2042 MSI controller.
Signed-off-by Chen Wang <[email protected]>--- .../sophgo,sg2042-msi.yaml | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+)create mode 100644
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yamlDocumentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +10
-0@@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/sophgo,sg2042-msi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sophgo SG2042 MSI Controller + +maintainers: + - Chen Wang <[email protected]>
Quoted 8 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 17
Quoted 7 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +7
-0+ +description: + This interrupt controller is in Sophgo SG2042 for transforming interrupts from + PCIe MSI to PLIC interrupts. + +allOf: + - $ref: /schemas/interrupts.yaml#Drop this.
I find if we drop this line, dtb check will report "Unevaluated properties are not allowed ('interrupt-parent' was unexpected)"
Do we still need to keep this?
Thanks,
Chen
Quoted 13 lines
Quoted 13 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +13
-0+ - $ref: /schemas/interrupt-controller/msi-controller.yaml# + +properties: + compatible: + const: sophgo,sg2042-msi + + reg: + items: + - description: msi doorbell address + - description: clear register + + reg-names: + items:
Quoted 8 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 37
Quoted 7 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +7
-0+ - const: doorbell + - const: clr + + msi-controller: true + + msi-ranges: + maxItems: 1You need #msi-cells.
OK, will add this.
Quoted 24 lines
Quoted 24 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +21
-0+ +required: + - compatible + - reg + - reg-names + - msi-controller + - msi-ranges + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + msi-controller@30000000 { + compatible = "sophgo,sg2042-msi"; + reg = <0x30000000 0x4>, <0x30000008 0x4>; + reg-names = "doorbell", "clr"; + msi-controller; + msi-ranges = <&plic 64 IRQ_TYPE_LEVEL_HIGH 32>; + interrupt-parent = <&plic>; + };Signature · 1 line
2.34.1
PATCH v3 2/3 irqchip: Add the Sophgo SG2042 MSI interrupt controller
In reply to Chen WangFrom: Chen Wang <[email protected]>
Add driver for Sophgo SG2042 MSI interrupt controller.
--- drivers/irqchip/Kconfig | 12 ++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-sg2042-msi.c | 268 +++++++++++++++++++++++++++++++ 3 files changed, 281 insertions(+) create mode 100644 drivers/irqchip/irq-sg2042-msi.c
drivers/irqchip/Kconfig +12 -0
@@ -749,6 +749,18 @@ config MCHP_EIC help Support for Microchip External Interrupt Controller. +config SOPHGO_SG2042_MSI + bool "Sophgo SG2042 MSI Controller" + depends on ARCH_SOPHGO || COMPILE_TEST + depends on PCI + select IRQ_DOMAIN_HIERARCHY + select IRQ_MSI_LIB + select PCI_MSI + help + Support for the Sophgo SG2042 MSI Controller. + This on-chip interrupt controller enables MSI sources to be + routed to the primary PLIC controller on SoC. + config SUNPLUS_SP7021_INTC bool "Sunplus SP7021 interrupt controller" if COMPILE_TEST default SOC_SP7021
drivers/irqchip/Makefile +1 -0
@@ -128,4 +128,5 @@ obj-$(CONFIG_WPCM450_AIC) += irq-wpcm450-aic.o obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o +obj-$(CONFIG_SOPHGO_SG2042_MSI) += irq-sg2042-msi.o obj-$(CONFIG_SUNPLUS_SP7021_INTC) += irq-sp7021-intc.o
drivers/irqchip/irq-sg2042-msi.c new file +268 -0
268 lines not on this page · raw message
Signature · 1 line
2.34.1
Inochi Amaoto
maintainerRe: [PATCH v3 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
Quoted 200 lines · Chen Wang
From: Chen Wang <[email protected]>
Add driver for Sophgo SG2042 MSI interrupt controller.
Signed-off-by Chen Wang <[email protected]>--- drivers/irqchip/Kconfig | 12 ++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-sg2042-msi.c | 268 +++++++++++++++++++++++++++++++ 3 files changed, 281 insertions(+) create mode 100644 drivers/irqchip/irq-sg2042-msi.cdrivers/irqchip/Kconfig +12
-0@@ -749,6 +749,18 @@ config MCHP_EIC help Support for Microchip External Interrupt Controller. +config SOPHGO_SG2042_MSI + bool "Sophgo SG2042 MSI Controller" + depends on ARCH_SOPHGO || COMPILE_TEST + depends on PCI + select IRQ_DOMAIN_HIERARCHY + select IRQ_MSI_LIB + select PCI_MSI + help + Support for the Sophgo SG2042 MSI Controller. + This on-chip interrupt controller enables MSI sources to be + routed to the primary PLIC controller on SoC. + config SUNPLUS_SP7021_INTC bool "Sunplus SP7021 interrupt controller" if COMPILE_TEST default SOC_SP7021drivers/irqchip/Makefile +1
-0@@ -128,4 +128,5 @@ obj-$(CONFIG_WPCM450_AIC) += irq-wpcm450-aic.o obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o +obj-$(CONFIG_SOPHGO_SG2042_MSI) += irq-sg2042-msi.o obj-$(CONFIG_SUNPLUS_SP7021_INTC) += irq-sp7021-intc.odrivers/irqchip/irq-sg2042-msi.c new file +149
-0@@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* SG2042 MSI Controller +* +* Copyright (C) 2024 Sophgo Technology Inc. +* Copyright (C) 2024 Chen Wang <[email protected]> +*/ + +#include <linux/cleanup.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/msi.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_pci.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "irq-msi-lib.h" + +#define SG2042_MAX_MSI_VECTOR 32 + +struct sg2042_msi_chipdata { +void __iomem *reg_clr;// clear reg, see TRM, 10.1.33, GP_INTR0_CLR + +phys_addr_t doorbell_addr;// see TRM, 10.1.32, GP_INTR0_SET + +u32 irq_first;// The vector number that MSIs starts +u32 num_irqs;// The number of vectors for MSIs + + DECLARE_BITMAP(msi_map, SG2042_MAX_MSI_VECTOR); +struct mutex msi_map_lock;// lock for msi_map +}; + +static int sg2042_msi_allocate_hwirq (struct sg2042_msi_chipdata *data,int num_req) +{ +int first; + +guard (mutex)(&data->msi_map_lock); + first =bitmap_find_free_region (data->msi_map, data->num_irqs, +get_count_order (num_req)); +return first >=0 ? first : -ENOSPC ; +} + +static void sg2042_msi_free_hwirq (struct sg2042_msi_chipdata *data, +int hwirq,int num_req) +{ +guard (mutex)(&data->msi_map_lock); +bitmap_release_region (data->msi_map, hwirq,get_count_order (num_req)); +} + +static void sg2042_msi_irq_ack (struct irq_data *d) +{ +struct sg2042_msi_chipdata *data =irq_data_get_irq_chip_data (d); +int bit_off = d->hwirq; + +writel (1 << bit_off, data->reg_clr); + +irq_chip_ack_parent (d); +} + +static void sg2042_msi_irq_compose_msi_msg (struct irq_data *d, +struct msi_msg *msg) +{ +struct sg2042_msi_chipdata *data =irq_data_get_irq_chip_data (d); + + msg->address_hi =upper_32_bits (data->doorbell_addr); + msg->address_lo =lower_32_bits (data->doorbell_addr); + msg->data =1 << d->hwirq; +} + +static const struct irq_chip sg2042_msi_middle_irq_chip = { + .name ="SG2042 MSI" , + .irq_ack = sg2042_msi_irq_ack, + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, +#ifdef CONFIG_SMP + .irq_set_affinity = irq_chip_set_affinity_parent, +#endif + .irq_compose_msi_msg = sg2042_msi_irq_compose_msi_msg, +}; + +static int sg2042_msi_parent_domain_alloc (struct irq_domain *domain, +unsigned int virq,int hwirq) +{ +struct sg2042_msi_chipdata *data = domain->host_data; +struct irq_fwspec fwspec; +struct irq_data *d; +int ret; + + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count =2 ; + fwspec.param[0 ] = data->irq_first + hwirq; + fwspec.param[1 ] =IRQ_TYPE_EDGE_RISING ; + + ret =irq_domain_alloc_irqs_parent (domain, virq,1 , &fwspec); +if (ret) +return ret; + + d =irq_domain_get_irq_data (domain->parent, virq); +return d->chip->irq_set_type (d,IRQ_TYPE_EDGE_RISING ); +} + +static int sg2042_msi_middle_domain_alloc (struct irq_domain *domain, +unsigned int virq, +unsigned int nr_irqs,void *args) +{ +struct sg2042_msi_chipdata *data = domain->host_data; +int hwirq, err, i; + + hwirq =sg2042_msi_allocate_hwirq (data, nr_irqs); +if (hwirq <0 ) +return hwirq; + +for (i =0 ; i < nr_irqs; i++) { + err =sg2042_msi_parent_domain_alloc (domain, virq + i, hwirq + i); +if (err) + goto err_hwirq; + +irq_domain_set_hwirq_and_chip (domain, virq + i, hwirq + i, + &sg2042_msi_middle_irq_chip, data); + } + +return 0 ; + +err_hwirq: +sg2042_msi_free_hwirq (data, hwirq, nr_irqs); +irq_domain_free_irqs_parent (domain, virq, i); + +return err; +} + +static void sg2042_msi_middle_domain_free (struct irq_domain *domain, +unsigned int virq, +unsigned int nr_irqs) +{ +struct irq_data *d =irq_domain_get_irq_data (domain, virq); +struct sg2042_msi_chipdata *data =irq_data_get_irq_chip_data (d); + +irq_domain_free_irqs_parent (domain, virq, nr_irqs); +sg2042_msi_free_hwirq (data, d->hwirq, nr_irqs); +} + +static const struct irq_domain_ops sg2042_msi_middle_domain_ops = { + .alloc = sg2042_msi_middle_domain_alloc,
drivers/irqchip/irq-sg2042-msi.c line 158
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +9
-0+ .free = sg2042_msi_middle_domain_free, + .select = msi_lib_irq_domain_select, +}; + +#define SG2042_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS) + +#define SG2042_MSI_FLAGS_SUPPORTED MSI_GENERIC_FLAGS_MASK +
I think it is just OK to set the flag directly in the msi_parent_ops.
drivers/irqchip/irq-sg2042-msi.c line 166
Quoted 8 lines
drivers/irqchip/irq-sg2042-msi.c new file +8
-0+static struct msi_parent_ops sg2042_msi_parent_ops = { + .required_flags =SG2042_MSI_FLAGS_REQUIRED , + .supported_flags =SG2042_MSI_FLAGS_SUPPORTED , + .bus_select_mask =MATCH_PCI_MSI , + .bus_select_token =DOMAIN_BUS_NEXUS , + .prefix ="SG2042-" , + .init_dev_msi_info = msi_lib_init_dev_msi_info, +};
This struct should be const.
Quoted 105 lines
drivers/irqchip/irq-sg2042-msi.c new file +102
-0+ +static int sg2042_msi_init_domains (struct sg2042_msi_chipdata *data, +struct device_node *node) +{ +struct fwnode_handle *fwnode =of_node_to_fwnode (node); +struct irq_domain *plic_domain, *middle_domain; +struct device_node *plic_node; + +if (!of_find_property (node,"interrupt-parent" ,NULL )) { +pr_err ("Can't find interrupt-parent!\n" ); +return -EINVAL ; + } + + plic_node =of_irq_find_parent (node); +if (!plic_node) { +pr_err ("Failed to find the PLIC node!\n" ); +return -ENXIO ; + } + + plic_domain =irq_find_host (plic_node); +of_node_put (plic_node); +if (!plic_domain) { +pr_err ("Failed to find the PLIC domain\n" ); +return -ENXIO ; + } + + middle_domain =irq_domain_create_hierarchy (plic_domain,0 , data->num_irqs, + fwnode, + &sg2042_msi_middle_domain_ops, + data); +if (!middle_domain) { +pr_err ("Failed to create the MSI middle domain\n" ); +return -ENOMEM ; + } + +irq_domain_update_bus_token (middle_domain,DOMAIN_BUS_NEXUS ); + + middle_domain->flags |=IRQ_DOMAIN_FLAG_MSI_PARENT ; + middle_domain->msi_parent_ops = &sg2042_msi_parent_ops; + +return 0 ; +} + +static int sg2042_msi_probe (struct platform_device *pdev) +{ +struct sg2042_msi_chipdata *data; +struct of_phandle_args args = {}; +struct resource *res; +int ret; + + data =devm_kzalloc (&pdev->dev,sizeof (struct sg2042_msi_chipdata ),GFP_KERNEL ); +if (!data) +return -ENOMEM ; + + data->reg_clr =devm_platform_ioremap_resource_byname (pdev,"clr" ); +if (IS_ERR (data->reg_clr)) { +dev_err (&pdev->dev,"Failed to map clear register\n" ); +return PTR_ERR (data->reg_clr); + } + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"doorbell" ); +if (!res) { +dev_err (&pdev->dev,"Failed get resource from set\n" ); +return -EINVAL ; + } + data->doorbell_addr = res->start; + + ret =of_parse_phandle_with_args (pdev->dev.of_node,"msi-ranges" , +"#interrupt-cells" ,0 , &args); +if (ret) { +dev_err (&pdev->dev,"Unable to parse MSI vec base\n" ); +return ret; + } + data->irq_first = (u32 )args.args[0 ]; + + ret =of_property_read_u32_index (pdev->dev.of_node,"msi-ranges" , + args.args_count +1 , &data->num_irqs); +if (ret) { +dev_err (&pdev->dev,"Unable to parse MSI vec number\n" ); +of_node_put (args.np); +return ret; + } +of_node_put (args.np); + +mutex_init (&data->msi_map_lock); + +return sg2042_msi_init_domains (data, pdev->dev.of_node); +} + +static const struct of_device_id sg2042_msi_of_match[] = { + { .compatible ="sophgo,sg2042-msi" }, + {} +}; + +static struct platform_driver sg2042_msi_driver = { + .driver = { + .name ="sg2042-msi" , + .of_match_table = sg2042_msi_of_match, + }, + .probe = sg2042_msi_probe, +}; +builtin_platform_driver (sg2042_msi_driver);Signature · 1 line
2.34.1
Re: [PATCH v3 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
Quoted 1 line · Inochi Amaoto
On Wed, Jan 15, 2025 at 02:33:45PM +0800, Chen Wang wrote:
[......]
Quoted 6 lines
drivers/irqchip/irq-sg2042-msi.c line 158
Quoted 5 lines
drivers/irqchip/irq-sg2042-msi.c new file +5
-0+#define SG2042_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS) + +#define SG2042_MSI_FLAGS_SUPPORTED MSI_GENERIC_FLAGS_MASK +I think it is just OK to set the flag directly in the
msi_parent_ops.
This shouldn't be a big problem, maybe it will be convenient for future expansion.
Quoted 9 lines
drivers/irqchip/irq-sg2042-msi.c line 166
Quoted 8 lines
drivers/irqchip/irq-sg2042-msi.c new file +8
-0+static struct msi_parent_ops sg2042_msi_parent_ops = { + .required_flags =SG2042_MSI_FLAGS_REQUIRED , + .supported_flags =SG2042_MSI_FLAGS_SUPPORTED , + .bus_select_mask =MATCH_PCI_MSI , + .bus_select_token =DOMAIN_BUS_NEXUS , + .prefix ="SG2042-" , + .init_dev_msi_info = msi_lib_init_dev_msi_info, +};This struct should be const.
Yes, will fix this in next version.
Thanks,
Chen
[......]
Inochi Amaoto
maintainerRe: [PATCH v3 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
In reply to Chen WangQuoted 210 lines · Chen Wang
From: Chen Wang <[email protected]>
Add driver for Sophgo SG2042 MSI interrupt controller.
Signed-off-by Chen Wang <[email protected]>--- drivers/irqchip/Kconfig | 12 ++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-sg2042-msi.c | 268 +++++++++++++++++++++++++++++++ 3 files changed, 281 insertions(+) create mode 100644 drivers/irqchip/irq-sg2042-msi.cdrivers/irqchip/Kconfig +12
-0@@ -749,6 +749,18 @@ config MCHP_EIC help Support for Microchip External Interrupt Controller. +config SOPHGO_SG2042_MSI + bool "Sophgo SG2042 MSI Controller" + depends on ARCH_SOPHGO || COMPILE_TEST + depends on PCI + select IRQ_DOMAIN_HIERARCHY + select IRQ_MSI_LIB + select PCI_MSI + help + Support for the Sophgo SG2042 MSI Controller. + This on-chip interrupt controller enables MSI sources to be + routed to the primary PLIC controller on SoC. + config SUNPLUS_SP7021_INTC bool "Sunplus SP7021 interrupt controller" if COMPILE_TEST default SOC_SP7021drivers/irqchip/Makefile +1
-0@@ -128,4 +128,5 @@ obj-$(CONFIG_WPCM450_AIC) += irq-wpcm450-aic.o obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o +obj-$(CONFIG_SOPHGO_SG2042_MSI) += irq-sg2042-msi.o obj-$(CONFIG_SUNPLUS_SP7021_INTC) += irq-sp7021-intc.odrivers/irqchip/irq-sg2042-msi.c new file +159
-0@@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* SG2042 MSI Controller +* +* Copyright (C) 2024 Sophgo Technology Inc. +* Copyright (C) 2024 Chen Wang <[email protected]> +*/ + +#include <linux/cleanup.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/msi.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_pci.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "irq-msi-lib.h" + +#define SG2042_MAX_MSI_VECTOR 32 + +struct sg2042_msi_chipdata { +void __iomem *reg_clr;// clear reg, see TRM, 10.1.33, GP_INTR0_CLR + +phys_addr_t doorbell_addr;// see TRM, 10.1.32, GP_INTR0_SET + +u32 irq_first;// The vector number that MSIs starts +u32 num_irqs;// The number of vectors for MSIs + + DECLARE_BITMAP(msi_map, SG2042_MAX_MSI_VECTOR); +struct mutex msi_map_lock;// lock for msi_map +}; + +static int sg2042_msi_allocate_hwirq (struct sg2042_msi_chipdata *data,int num_req) +{ +int first; + +guard (mutex)(&data->msi_map_lock); + first =bitmap_find_free_region (data->msi_map, data->num_irqs, +get_count_order (num_req)); +return first >=0 ? first : -ENOSPC ; +} + +static void sg2042_msi_free_hwirq (struct sg2042_msi_chipdata *data, +int hwirq,int num_req) +{ +guard (mutex)(&data->msi_map_lock); +bitmap_release_region (data->msi_map, hwirq,get_count_order (num_req)); +} + +static void sg2042_msi_irq_ack (struct irq_data *d) +{ +struct sg2042_msi_chipdata *data =irq_data_get_irq_chip_data (d); +int bit_off = d->hwirq; + +writel (1 << bit_off, data->reg_clr); + +irq_chip_ack_parent (d); +} + +static void sg2042_msi_irq_compose_msi_msg (struct irq_data *d, +struct msi_msg *msg) +{ +struct sg2042_msi_chipdata *data =irq_data_get_irq_chip_data (d); + + msg->address_hi =upper_32_bits (data->doorbell_addr); + msg->address_lo =lower_32_bits (data->doorbell_addr); + msg->data =1 << d->hwirq; +} + +static const struct irq_chip sg2042_msi_middle_irq_chip = { + .name ="SG2042 MSI" , + .irq_ack = sg2042_msi_irq_ack, + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, +#ifdef CONFIG_SMP + .irq_set_affinity = irq_chip_set_affinity_parent, +#endif + .irq_compose_msi_msg = sg2042_msi_irq_compose_msi_msg, +}; + +static int sg2042_msi_parent_domain_alloc (struct irq_domain *domain, +unsigned int virq,int hwirq) +{ +struct sg2042_msi_chipdata *data = domain->host_data; +struct irq_fwspec fwspec; +struct irq_data *d; +int ret; + + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count =2 ; + fwspec.param[0 ] = data->irq_first + hwirq; + fwspec.param[1 ] =IRQ_TYPE_EDGE_RISING ; + + ret =irq_domain_alloc_irqs_parent (domain, virq,1 , &fwspec); +if (ret) +return ret; + + d =irq_domain_get_irq_data (domain->parent, virq); +return d->chip->irq_set_type (d,IRQ_TYPE_EDGE_RISING ); +} + +static int sg2042_msi_middle_domain_alloc (struct irq_domain *domain, +unsigned int virq, +unsigned int nr_irqs,void *args) +{ +struct sg2042_msi_chipdata *data = domain->host_data; +int hwirq, err, i; + + hwirq =sg2042_msi_allocate_hwirq (data, nr_irqs); +if (hwirq <0 ) +return hwirq; + +for (i =0 ; i < nr_irqs; i++) { + err =sg2042_msi_parent_domain_alloc (domain, virq + i, hwirq + i); +if (err) + goto err_hwirq; + +irq_domain_set_hwirq_and_chip (domain, virq + i, hwirq + i, + &sg2042_msi_middle_irq_chip, data); + } + +return 0 ; + +err_hwirq: +sg2042_msi_free_hwirq (data, hwirq, nr_irqs); +irq_domain_free_irqs_parent (domain, virq, i); + +return err; +} + +static void sg2042_msi_middle_domain_free (struct irq_domain *domain, +unsigned int virq, +unsigned int nr_irqs) +{ +struct irq_data *d =irq_domain_get_irq_data (domain, virq); +struct sg2042_msi_chipdata *data =irq_data_get_irq_chip_data (d); + +irq_domain_free_irqs_parent (domain, virq, nr_irqs); +sg2042_msi_free_hwirq (data, d->hwirq, nr_irqs); +} + +static const struct irq_domain_ops sg2042_msi_middle_domain_ops = { + .alloc = sg2042_msi_middle_domain_alloc, + .free = sg2042_msi_middle_domain_free, + .select = msi_lib_irq_domain_select, +}; + +#define SG2042_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS) + +#define SG2042_MSI_FLAGS_SUPPORTED MSI_GENERIC_FLAGS_MASK + +static struct msi_parent_ops sg2042_msi_parent_ops = {
drivers/irqchip/irq-sg2042-msi.c line 169
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+ .required_flags = SG2042_MSI_FLAGS_REQUIRED, + .supported_flags = SG2042_MSI_FLAGS_SUPPORTED, + .bus_select_mask = MATCH_PCI_MSI, + .bus_select_token = DOMAIN_BUS_NEXUS, + .prefix = "SG2042-", + .init_dev_msi_info = msi_lib_init_dev_msi_info, +}; + +static int sg2042_msi_init_domains (struct sg2042_msi_chipdata *data, +struct device_node *node)
For ACPI support, I prefer to use device instead of device_node The following suggestion is also for ACPI support
Quoted 7 lines
drivers/irqchip/irq-sg2042-msi.c new file +6
-0+{ +struct fwnode_handle *fwnode =of_node_to_fwnode (node); +struct irq_domain *plic_domain, *middle_domain; +struct device_node *plic_node; + +if (!of_find_property (node,"interrupt-parent" ,NULL )) {
drivers/irqchip/irq-sg2042-msi.c line 185
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+pr_err ("Can't find interrupt-parent!\n" ); +return -EINVAL ; + } + + plic_node =of_irq_find_parent (node); +if (!plic_node) { +pr_err ("Failed to find the PLIC node!\n" ); +return -ENXIO ; + } +
This can be replace with fwnode_find_reference to support ACPI
drivers/irqchip/irq-sg2042-msi.c line 192
Quoted 7 lines
drivers/irqchip/irq-sg2042-msi.c new file +7
-0+ plic_domain =irq_find_host (plic_node); +of_node_put (plic_node); +if (!plic_domain) { +pr_err ("Failed to find the PLIC domain\n" ); +return -ENXIO ; + } +
Replace irq_find_host with irq_find_matching_fwnode
drivers/irqchip/irq-sg2042-msi.c line 196
Quoted 4 lines
drivers/irqchip/irq-sg2042-msi.c new file +4
-0+ middle_domain =irq_domain_create_hierarchy (plic_domain,0 , data->num_irqs, + fwnode, + &sg2042_msi_middle_domain_ops, + data);
Use irq_domain_create_hierarchy
Quoted 5 lines
drivers/irqchip/irq-sg2042-msi.c new file +5
-0+if (!middle_domain) { +pr_err ("Failed to create the MSI middle domain\n" ); +return -ENOMEM ; + } +
drivers/irqchip/irq-sg2042-msi.c line 211
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+irq_domain_update_bus_token (middle_domain,DOMAIN_BUS_NEXUS ); + + middle_domain->flags |=IRQ_DOMAIN_FLAG_MSI_PARENT ; + middle_domain->msi_parent_ops = &sg2042_msi_parent_ops; + +return 0 ; +} + +static int sg2042_msi_probe (struct platform_device *pdev) +{
add a "struct device *dev = &pdev->dev;" here and replace &pdev->dev with dev.
Quoted 29 lines
drivers/irqchip/irq-sg2042-msi.c new file +28
-0+struct sg2042_msi_chipdata *data; +struct of_phandle_args args = {}; +struct resource *res; +int ret; + + data =devm_kzalloc (&pdev->dev,sizeof (struct sg2042_msi_chipdata ),GFP_KERNEL ); +if (!data) +return -ENOMEM ; + + data->reg_clr =devm_platform_ioremap_resource_byname (pdev,"clr" ); +if (IS_ERR (data->reg_clr)) { +dev_err (&pdev->dev,"Failed to map clear register\n" ); +return PTR_ERR (data->reg_clr); + } + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"doorbell" ); +if (!res) { +dev_err (&pdev->dev,"Failed get resource from set\n" ); +return -EINVAL ; + } + data->doorbell_addr = res->start; + + ret =of_parse_phandle_with_args (pdev->dev.of_node,"msi-ranges" , +"#interrupt-cells" ,0 , &args); +if (ret) { +dev_err (&pdev->dev,"Unable to parse MSI vec base\n" ); +return ret; + }
drivers/irqchip/irq-sg2042-msi.c line 249
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+ data->irq_first = (u32 )args.args[0 ]; + + ret =of_property_read_u32_index (pdev->dev.of_node,"msi-ranges" , + args.args_count +1 , &data->num_irqs); +if (ret) { +dev_err (&pdev->dev,"Unable to parse MSI vec number\n" ); +of_node_put (args.np); +return ret; + } +of_node_put (args.np);
this can be replace by calling fwnode_property_get_reference_args twice. I have found a working example:
ret = fwnode_property_get_reference_args(dev_fwnode(dev), "msi-ranges",
"#interrupt-cells",
0, 0, &args);
if (ret) {
dev_err(dev, "Unable to parse MSI vec base\n");
return ret;
}fwnode_handle_put(args.fwnode);
ret = fwnode_property_get_reference_args(dev_fwnode(dev), "msi-ranges",
NULL, args.nargs + 1,
0, &args);
if (ret) {
dev_err(dev, "Unable to parse MSI vec number\n");
return ret;
}data->irq_first = (u32)args.args[0];data->num_irqs = (u32)args.args[args.nargs - 1];
fwnode_handle_put(args.fwnode);
Regards,
Inochi
Re: [PATCH v3 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
Quoted 1 line · Inochi Amaoto
On Wed, Jan 15, 2025 at 02:33:45PM +0800, Chen Wang wrote:
[......]
Quoted 5 lines
drivers/irqchip/irq-sg2042-msi.c line 196
Quoted 4 lines
drivers/irqchip/irq-sg2042-msi.c new file +4
-0+ middle_domain =irq_domain_create_hierarchy (plic_domain,0 , data->num_irqs, + fwnode, + &sg2042_msi_middle_domain_ops, + data);Use
irq_domain_create_hierarchy
What's the difference?
[......]
Inochi Amaoto
maintainerRe: [PATCH v3 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
Quoted 12 lines · Chen Wang
Quoted 1 line · Inochi Amaoto
On Wed, Jan 15, 2025 at 02:33:45PM +0800, Chen Wang wrote:
[......]
Quoted 5 lines
drivers/irqchip/irq-sg2042-msi.c line 196
Quoted 4 lines
drivers/irqchip/irq-sg2042-msi.c new file +4
-0+ middle_domain =irq_domain_create_hierarchy (plic_domain,0 , data->num_irqs, + fwnode, + &sg2042_msi_middle_domain_ops, + data);Use
irq_domain_create_hierarchyWhat's the difference?
I made a mistake, just ignore it. The original is OK.
Regard,
Inochi
PATCH v3 3/3 riscv: sophgo: dts: add msi controller for SG2042
In reply to Chen WangFrom: Chen Wang <[email protected]>
Add msi-controller node to dts for SG2042.
--- arch/riscv/boot/dts/sophgo/sg2042.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/riscv/boot/dts/sophgo/sg2042.dtsi +10 -0
@@ -173,6 +173,16 @@ pllclk: clock-controller@70300100c0 { #clock-cells = <1>; }; + msi: msi-controller@7030010300 { + compatible = "sophgo,sg2042-msi"; + reg = <0x70 0x30010300 0x0 0x4>, + <0x70 0x30010304 0x0 0x4>; + reg-names = "doorbell", "clr"; + msi-controller; + msi-ranges = <&intc 64 IRQ_TYPE_LEVEL_HIGH 32>; + interrupt-parent = <&intc>; + }; + rpgate: clock-controller@7030010368 { compatible = "sophgo,sg2042-rpgate"; reg = <0x70 0x30010368 0x0 0x98>;
Signature · 1 line
2.34.1