irqchip: Add Sophgo SG2042 MSI controller
v4 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 v4:
The patch series is based on v6.14-rc1.
Fixed following issues as per comments from Inochi Amaoto, Rob Herring, thanks.
- bindings:
- Update sequence of "reg-names".
- Remove reference to/schemas/interrupts.yaml
- Add "#msi-cells".
- Improve driver code:
- Use fwnode_* instead of of_*.
- Some other coding style improvements.
Changes in v3:
The patch series is based on v6.13-rc7. You can simply review or test the patches at the link [3].
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 | 61 ++++ arch/riscv/boot/dts/sophgo/sg2042.dtsi | 10 + drivers/irqchip/Kconfig | 12 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-sg2042-msi.c | 264 ++++++++++++++++++ 5 files changed, 348 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml create mode 100644 drivers/irqchip/irq-sg2042-msi.c
base-commit: 2014c95afecee3e76ca4a56956a936e23283f05b
Signature · 1 line
2.34.1
PATCH v4 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 | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +61 -0
@@ -0,0 +1,61 @@ +# 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/interrupt-controller/msi-controller.yaml# + +properties: + compatible: + const: sophgo,sg2042-msi + + reg: + items: + - description: clear register + - description: msi doorbell address + + reg-names: + items: + - const: clr + - const: doorbell + + msi-controller: true + + msi-ranges: + maxItems: 1 + + "#msi-cells": + const: 0 + +required: + - compatible + - reg + - reg-names + - msi-controller + - msi-ranges + - "#msi-cells" + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + msi-controller@30000000 { + compatible = "sophgo,sg2042-msi"; + reg = <0x30000000 0x4>, <0x30000008 0x4>; + reg-names = "clr", "doorbell"; + msi-controller; + #msi-cells = <0>; + msi-ranges = <&plic 64 IRQ_TYPE_LEVEL_HIGH 32>; + };
Signature · 1 line
2.34.1
Re: [PATCH v4 1/3] dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
Quoted 10 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 | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml
PATCH v4 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 | 264 +++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 drivers/irqchip/irq-sg2042-msi.c
drivers/irqchip/Kconfig +12 -0
@@ -751,6 +751,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 +264 -0
264 lines not on this page · raw message
Signature · 1 line
2.34.1
Re: [PATCH v4 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
Quoted 218 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 | 264 +++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 drivers/irqchip/irq-sg2042-msi.cdrivers/irqchip/Kconfig +12
-0@@ -751,6 +751,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 +167
-0@@ -0,0 +1,264 @@ +// 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/platform_device.h> +#include <linux/property.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 const 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, +}; + +static int sg2042_msi_init_domains (struct sg2042_msi_chipdata *data, +struct device *dev) +{
drivers/irqchip/irq-sg2042-msi.c line 176
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +9
-0+struct fwnode_handle *fwnode =dev_fwnode (dev); +struct irq_domain *plic_domain, *middle_domain; +struct fwnode_handle *plic_node; + + plic_node =fwnode_find_reference (fwnode,"msi-ranges" ,0 ); +if (IS_ERR (plic_node)) { +pr_err ("Failed to find the PLIC node!\n" ); +return PTR_ERR (plic_node); + }
I think plic_node is just the args.fwnode in the sg2042_msi_probe. Just reuse it. No need to parse this again.
Otherwise, It looks good to me. With this fix:
Quoted 91 lines
drivers/irqchip/irq-sg2042-msi.c new file +88
-0+ + plic_domain =irq_find_matching_fwnode (plic_node,DOMAIN_BUS_ANY ); +fwnode_handle_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 fwnode_reference_args args = {}; +struct sg2042_msi_chipdata *data; +struct device *dev = &pdev->dev; +struct resource *res; +int ret; + + data =devm_kzalloc (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 (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 (dev,"Failed get resource from set\n" ); +return -EINVAL ; + } + data->doorbell_addr = res->start; + + 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; + } +fwnode_handle_put (args.fwnode); + + data->irq_first = (u32 )args.args[0 ]; + data->num_irqs = (u32 )args.args[args.nargs -1 ]; + +mutex_init (&data->msi_map_lock); + +return sg2042_msi_init_domains (data, dev); +} + +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 v4 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
On 2025/2/21 14:35, Inochi Amaoto wrote:
[......]
Quoted 15 lines
drivers/irqchip/irq-sg2042-msi.c line 176
Quoted 12 lines
drivers/irqchip/irq-sg2042-msi.c new file +12
-0+static int sg2042_msi_init_domains (struct sg2042_msi_chipdata *data, +struct device *dev) +{ +struct fwnode_handle *fwnode =dev_fwnode (dev); +struct irq_domain *plic_domain, *middle_domain; +struct fwnode_handle *plic_node; + + plic_node =fwnode_find_reference (fwnode,"msi-ranges" ,0 ); +if (IS_ERR (plic_node)) { +pr_err ("Failed to find the PLIC node!\n" ); +return PTR_ERR (plic_node); + }I think
plic_nodeis just the args.fwnode in thesg2042_msi_probe. Just reuse it. No need to parse this again.
Quoted 3 lines
Otherwise, It looks good to me. With this fix:
Reviewed-by Inochi Amaoto <[email protected]>
Thanks, I will fix this.
Regards,
Chen
[......]
PATCH v4 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@7030010304 { + compatible = "sophgo,sg2042-msi"; + reg = <0x70 0x30010304 0x0 0x4>, + <0x70 0x30010300 0x0 0x4>; + reg-names = "clr", "doorbell"; + msi-controller; + #msi-cells = <0>; + msi-ranges = <&intc 64 IRQ_TYPE_LEVEL_HIGH 32>; + }; + rpgate: clock-controller@7030010368 { compatible = "sophgo,sg2042-rpgate"; reg = <0x70 0x30010368 0x0 0x98>;
Signature · 1 line
2.34.1