irqchip: Add Sophgo SG2042 MSI controller
v2 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 v2:
The patch series is based on v6.13-rc2.
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 | 63 ++++ arch/riscv/boot/dts/sophgo/sg2042.dtsi | 10 + drivers/irqchip/Kconfig | 12 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-sg2042-msi.c | 285 ++++++++++++++++++ 5 files changed, 371 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml create mode 100644 drivers/irqchip/irq-sg2042-msi.c
base-commit: fac04efc5c793dccbd07e2d59af9f90b7fc0dca4
Signature · 1 line
2.34.1
PATCH v2 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 | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +63 -0
@@ -0,0 +1,63 @@ +# 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: clear register + + reg-names: + items: + - const: clr + + msi-controller: true + + msi-ranges: + maxItems: 1 + + sophgo,msi-doorbell-addr: + description: + u64 value of the MSI doorbell address + $ref: /schemas/types.yaml#/definitions/uint64 + +required: + - compatible + - reg + - reg-names + - msi-controller + - msi-ranges + - sophgo,msi-doorbell-addr + +additionalProperties: true + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + msi: msi-controller@30000000 { + compatible = "sophgo,sg2042-msi"; + reg = <0x30000000 0x4>; + reg-names = "clr"; + msi-controller; + msi-ranges = <&plic 64 IRQ_TYPE_LEVEL_HIGH 32>; + sophgo,msi-doorbell-addr = <0x00000070 0x30010300>; + interrupt-parent = <&plic>; + };
Signature · 1 line
2.34.1
Re: [PATCH v2 1/3] dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 40
Quoted 9 lines · Chen Wang
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +9
-0+ msi-controller: true + + msi-ranges: + maxItems: 1 + + sophgo,msi-doorbell-addr: + description: + u64 value of the MSI doorbell address + $ref: /schemas/types.yaml#/definitions/uint64
reg, as asked last time. 'reg' does not mean you need to ioremap it.
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 50
Quoted 10 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +10
-0+ +required: + - compatible + - reg + - reg-names + - msi-controller + - msi-ranges + - sophgo,msi-doorbell-addr + +additionalProperties: true
Nope, this cannot be true. There is no single device binding like that, so do not introduce your own conventions.
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 55
Quoted 5 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +5
-0+ +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + msi: msi-controller@30000000 {
Drop unused label.
Best regards,
Krzysztof
Re: [PATCH v2 1/3] dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
Quoted 11 lines · Krzysztof Kozlowski
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 40
Quoted 9 lines · Chen Wang
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +9
-0+ msi-controller: true + + msi-ranges: + maxItems: 1 + + sophgo,msi-doorbell-addr: + description: + u64 value of the MSI doorbell address + $ref: /schemas/types.yaml#/definitions/uint64reg, as asked last time. 'reg' does not mean you need to ioremap it.
Ok, I will fix this in next version.
Quoted 4 lines
Quoted 4 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +4
-0+ +required: + - compatible + - reg
Quoted 8 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 50
Quoted 6 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +6
-0+ - reg-names + - msi-controller + - msi-ranges + - sophgo,msi-doorbell-addr + +additionalProperties: trueNope, this cannot be true. There is no single device binding like that, so do not introduce your own conventions.
Got, will fix it.
Quoted 7 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml line 55
Quoted 6 lines
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml new file +5
-0+ +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + msi: msi-controller@30000000 {Drop unused label.
Got, thanks.
Quoted 4 lines
Best regards,
Krzysztof
PATCH v2 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 | 285 +++++++++++++++++++++++++++++++ 3 files changed, 298 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 +285 -0
285 lines not on this page · raw message
Signature · 1 line
2.34.1
Re: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
Quoted 11 lines · Chen Wang
drivers/irqchip/irq-sg2042-msi.c new file +11
-0+static void sg2042_msi_irq_ack (struct irq_data *d) +{ +struct sg2042_msi_data *data =irq_data_get_irq_chip_data (d); +int bit_off = d->hwirq - data->irq_first; + +writel (1 << bit_off, (unsigned int *)data->reg_clr); + +irq_chip_ack_parent (d); +} + +static void sg2042_msi_irq_compose_msi_msg(struct irq_data *data,
drivers/irqchip/irq-sg2042-msi.c line 79
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+ struct msi_msg *msg) +{ +struct sg2042_msi_data *priv =irq_data_get_irq_chip_data (data); + + msg->address_hi =upper_32_bits (priv->doorbell_addr); + msg->address_lo =lower_32_bits (priv->doorbell_addr); + msg->data =1 << (data->hwirq - priv->irq_first); + +pr_debug ("%s hwirq[%ld]: address_hi[%#x], address_lo[%#x], data[%#x]\n" , + __func__, data->hwirq, msg->address_hi, msg->address_lo, msg->data);
Don't print addresses, it is useless - it will be a constant.
Quoted 12 lines
drivers/irqchip/irq-sg2042-msi.c new file +12
-0+} + +static 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, +};
...
Quoted 18 lines
drivers/irqchip/irq-sg2042-msi.c new file +18
-0+static int sg2042_msi_probe (struct platform_device *pdev) +{ +struct of_phandle_args args = {}; +struct sg2042_msi_data *data; +int ret; + + data =devm_kzalloc (&pdev->dev,sizeof (struct sg2042_msi_data ),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); + } + +if (of_property_read_u64 (pdev->dev.of_node,"sophgo,msi-doorbell-addr" , + &data->doorbell_addr)) {
drivers/irqchip/irq-sg2042-msi.c line 244
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+dev_err (&pdev->dev,"Unable to parse MSI doorbell addr\n" ); +return -EINVAL ; + } + + 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; + }
You leak the phandle. You leak much more, btw...
Quoted 8 lines
drivers/irqchip/irq-sg2042-msi.c new file +8
-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" ); +return ret; + }
drivers/irqchip/irq-sg2042-msi.c line 262
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+ +if (data->irq_first <SG2042_VECTOR_MIN || + (data->irq_first + data->num_irqs -1 ) >SG2042_VECTOR_MAX ) { +dev_err (&pdev->dev,"msi-ranges is incorrect!\n" ); +return -EINVAL ; + } + +mutex_init (&data->msi_map_lock); + + data->msi_map =bitmap_zalloc (data->num_irqs,GFP_KERNEL );
This also leaks during removal.
Quoted 9 lines
drivers/irqchip/irq-sg2042-msi.c new file +9
-0+if (!data->msi_map) +return -ENOMEM ; + + ret =sg2042_msi_init_domains (data, pdev->dev.of_node); +if (ret) +bitmap_free (data->msi_map); + +return ret; +}
drivers/irqchip/irq-sg2042-msi.c line 281
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+ +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 =of_match_ptr (sg2042_msi_of_match),
Drop of_match_ptr(), unnecessary and might lead to warnings even if this is not a module.
Best regards,
Krzysztof
Re: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
Quoted 15 lines · Krzysztof Kozlowski
Quoted 14 lines · Chen Wang
drivers/irqchip/irq-sg2042-msi.c new file +14
-0+static void sg2042_msi_irq_ack (struct irq_data *d) +{ +struct sg2042_msi_data *data =irq_data_get_irq_chip_data (d); +int bit_off = d->hwirq - data->irq_first; + +writel (1 << bit_off, (unsigned int *)data->reg_clr); + +irq_chip_ack_parent (d); +} + +static void sg2042_msi_irq_compose_msi_msg (struct irq_data *data, +struct msi_msg *msg) +{ +struct sg2042_msi_data *priv =irq_data_get_irq_chip_data (data);
Quoted 8 lines
drivers/irqchip/irq-sg2042-msi.c line 79
Quoted 7 lines
drivers/irqchip/irq-sg2042-msi.c new file +7
-0+ + msg->address_hi =upper_32_bits (priv->doorbell_addr); + msg->address_lo =lower_32_bits (priv->doorbell_addr); + msg->data =1 << (data->hwirq - priv->irq_first); + +pr_debug ("%s hwirq[%ld]: address_hi[%#x], address_lo[%#x], data[%#x]\n" , + __func__, data->hwirq, msg->address_hi, msg->address_lo, msg->data);Don't print addresses, it is useless - it will be a constant.
Ok.
Quoted 36 lines
Quoted 13 lines
drivers/irqchip/irq-sg2042-msi.c new file +12
-0+} + +static 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, +};...
Quoted 21 lines
drivers/irqchip/irq-sg2042-msi.c new file +21
-0+static int sg2042_msi_probe (struct platform_device *pdev) +{ +struct of_phandle_args args = {}; +struct sg2042_msi_data *data; +int ret; + + data =devm_kzalloc (&pdev->dev,sizeof (struct sg2042_msi_data ),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); + } + +if (of_property_read_u64 (pdev->dev.of_node,"sophgo,msi-doorbell-addr" , + &data->doorbell_addr)) { +dev_err (&pdev->dev,"Unable to parse MSI doorbell addr\n" ); +return -EINVAL ; + }
Quoted 8 lines
drivers/irqchip/irq-sg2042-msi.c line 244
Quoted 7 lines
drivers/irqchip/irq-sg2042-msi.c new file +7
-0+ + 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; + }You leak the phandle. You leak much more, btw...
I will double-check, thanks.
Quoted 12 lines
Quoted 12 lines
drivers/irqchip/irq-sg2042-msi.c new file +11
-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" ); +return ret; + } + +if (data->irq_first <SG2042_VECTOR_MIN || + (data->irq_first + data->num_irqs -1 ) >SG2042_VECTOR_MAX ) {
Quoted 8 lines
drivers/irqchip/irq-sg2042-msi.c line 262
Quoted 7 lines
drivers/irqchip/irq-sg2042-msi.c new file +7
-0+dev_err (&pdev->dev,"msi-ranges is incorrect!\n" ); +return -EINVAL ; + } + +mutex_init (&data->msi_map_lock); + + data->msi_map =bitmap_zalloc (data->num_irqs,GFP_KERNEL );This also leaks during removal.
Got, thanks.
Quoted 14 lines
Quoted 14 lines
drivers/irqchip/irq-sg2042-msi.c new file +13
-0+if (!data->msi_map) +return -ENOMEM ; + + ret =sg2042_msi_init_domains (data, pdev->dev.of_node); +if (ret) +bitmap_free (data->msi_map); + +return ret; +} + +static const struct of_device_id sg2042_msi_of_match[] = { + { .compatible ="sophgo,sg2042-msi" }, + {}
Quoted 8 lines
drivers/irqchip/irq-sg2042-msi.c line 281
Quoted 6 lines
drivers/irqchip/irq-sg2042-msi.c new file +6
-0+}; + +static struct platform_driver sg2042_msi_driver = { + .driver = { + .name ="sg2042-msi" , + .of_match_table =of_match_ptr (sg2042_msi_of_match),Drop
of_match_ptr(), unnecessary and might lead to warnings even if this is not a module.
Got, I will remove it, thanks.
Quoted 4 lines
Best regards,
Krzysztof
kernel test robot
build botRe: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
In reply to Chen Wangkernel test robot noticed the following build warnings:
Hi Chen,
kernel test robot noticed the following build warnings:
[auto build test WARNING on fac04efc5c793dccbd07e2d59af9f90b7fc0dca4]
url: https://github.com/intel-lab-lkp/linux/commits/Chen-Wang/dt-bindings-interrupt-controller-Add-Sophgo-SG2042-MSI/20241209-151429 base: fac04efc5c793dccbd07e2d59af9f90b7fc0dca4 patch link: https://lore.kernel.org/r/c882fe329932409131be76ce47b81a6155595ce4.1733726057.git.unicorn_wang%40outlook.com patch subject: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller config: arm-randconfig-r131-20241210 (https://download.01.org/0day-ci/archive/20241210/[email protected]/config) compiler: arm-linux-gnueabi-gcc (GCC) 14.2.0 reproduce: (https://download.01.org/0day-ci/archive/20241210/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
sparse warnings: (new ones prefixed by >>)
>> drivers/irqchip/irq-sg2042-msi.c:64:9: sparse: sparse: cast removes address space '__iomem' of expression >> drivers/irqchip/irq-sg2042-msi.c:64:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got unsigned int * @@
drivers/irqchip/irq-sg2042-msi.c:64:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/irqchip/irq-sg2042-msi.c:64:9: sparse: got unsigned int *
vim +/__iomem +64 drivers/irqchip/irq-sg2042-msi.c
58
59 static void sg2042_msi_irq_ack(struct irq_data *d)
60 {
61 struct sg2042_msi_data *data = irq_data_get_irq_chip_data(d);
62 int bit_off = d->hwirq - data->irq_first;
63
> 64 writel(1 << bit_off, (unsigned int *)data->reg_clr);
65
66 irq_chip_ack_parent(d);
67 }
68 Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
kernel test robot
build botRe: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
In reply to Chen Wangkernel test robot noticed the following build warnings:
Hi Chen,
kernel test robot noticed the following build warnings:
[auto build test WARNING on fac04efc5c793dccbd07e2d59af9f90b7fc0dca4]
url: https://github.com/intel-lab-lkp/linux/commits/Chen-Wang/dt-bindings-interrupt-controller-Add-Sophgo-SG2042-MSI/20241209-151429 base: fac04efc5c793dccbd07e2d59af9f90b7fc0dca4 patch link: https://lore.kernel.org/r/c882fe329932409131be76ce47b81a6155595ce4.1733726057.git.unicorn_wang%40outlook.com patch subject: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller config: arm-randconfig-r131-20241210 (https://download.01.org/0day-ci/archive/20241211/[email protected]/config) compiler: arm-linux-gnueabi-gcc (GCC) 14.2.0 reproduce: (https://download.01.org/0day-ci/archive/20241211/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
sparse warnings: (new ones prefixed by >>)
>> drivers/irqchip/irq-sg2042-msi.c:64:9: sparse: sparse: cast removes address space '__iomem' of expression >> drivers/irqchip/irq-sg2042-msi.c:64:9: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void volatile [noderef] __iomem *addr @@ got unsigned int * @@
drivers/irqchip/irq-sg2042-msi.c:64:9: sparse: expected void volatile [noderef] __iomem *addr
drivers/irqchip/irq-sg2042-msi.c:64:9: sparse: got unsigned int *
vim +/__iomem +64 drivers/irqchip/irq-sg2042-msi.c
58
59 static void sg2042_msi_irq_ack(struct irq_data *d)
60 {
61 struct sg2042_msi_data *data = irq_data_get_irq_chip_data(d);
62 int bit_off = d->hwirq - data->irq_first;
63
> 64 writel(1 << bit_off, (unsigned int *)data->reg_clr);
65
66 irq_chip_ack_parent(d);
67 }
68 Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
kernel test robot
build botRe: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
In reply to Chen Wangkernel test robot noticed the following build warnings:
Hi Chen,
kernel test robot noticed the following build warnings:
[auto build test WARNING on fac04efc5c793dccbd07e2d59af9f90b7fc0dca4]
url: https://github.com/intel-lab-lkp/linux/commits/Chen-Wang/dt-bindings-interrupt-controller-Add-Sophgo-SG2042-MSI/20241209-151429 base: fac04efc5c793dccbd07e2d59af9f90b7fc0dca4 patch link: https://lore.kernel.org/r/c882fe329932409131be76ce47b81a6155595ce4.1733726057.git.unicorn_wang%40outlook.com patch subject: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller config: alpha-randconfig-r063-20241211 (https://download.01.org/0day-ci/archive/20241211/[email protected]/config) compiler: alpha-linux-gcc (GCC) 14.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241211/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
>> drivers/irqchip/irq-sg2042-msi.c:273:34: warning: 'sg2042_msi_of_match' defined but not used [-Wunused-const-variable=]
273 | static const struct of_device_id sg2042_msi_of_match[] = {
| ^~~~~~~~~~~~~~~~~~~vim +/sg2042_msi_of_match +273 drivers/irqchip/irq-sg2042-msi.c
272
> 273 static const struct of_device_id sg2042_msi_of_match[] = { 274 { .compatible = "sophgo,sg2042-msi" },
275 {}
276 };
277
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
Re: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
In reply to Chen WangQuoted 88 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 | 285 +++++++++++++++++++++++++++++++ 3 files changed, 298 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 +37
-0@@ -0,0 +1,285 @@ +// 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_VECTOR_MIN 64 +#define SG2042_VECTOR_MAX 95 + +struct sg2042_msi_data { +void __iomem *reg_clr;// clear reg, see TRM, 10.1.33, GP_INTR0_CLR + +u64 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 + +unsigned long *msi_map; +struct mutex msi_map_lock;// lock for msi_map
drivers/irqchip/irq-sg2042-msi.c line 47
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+}; + +static int sg2042_msi_allocate_hwirq (struct sg2042_msi_data *priv,int num_req) +{ +int first; + +guard (mutex)(&priv->msi_map_lock); + first =bitmap_find_free_region (priv->msi_map, priv->num_irqs, +get_count_order (num_req)); +return first >=0 ? priv->irq_first + first : -ENOSPC ;
How does this work? The irqdomain is instantiated with size == priv->num_irqs, so hwirqs must be less than priv->num_irqs. It also quite simplifies the code for hwirq be a number between 0 and priv->num_irqs. You only need to apply the offset when allocating the parent IRQ:
fwspec.param[0] = priv->irq_first + hwirq;
Quoted 238 lines
drivers/irqchip/irq-sg2042-msi.c new file +238
-0+} + +static void sg2042_msi_free_hwirq (struct sg2042_msi_data *priv, +int hwirq,int num_req) +{ +int first = hwirq - priv->irq_first; + +guard (mutex)(&priv->msi_map_lock); +bitmap_release_region (priv->msi_map, first,get_count_order (num_req)); +} + +static void sg2042_msi_irq_ack (struct irq_data *d) +{ +struct sg2042_msi_data *data =irq_data_get_irq_chip_data (d); +int bit_off = d->hwirq - data->irq_first; + +writel (1 << bit_off, (unsigned int *)data->reg_clr); + +irq_chip_ack_parent (d); +} + +static void sg2042_msi_irq_compose_msi_msg (struct irq_data *data, +struct msi_msg *msg) +{ +struct sg2042_msi_data *priv =irq_data_get_irq_chip_data (data); + + msg->address_hi =upper_32_bits (priv->doorbell_addr); + msg->address_lo =lower_32_bits (priv->doorbell_addr); + msg->data =1 << (data->hwirq - priv->irq_first); + +pr_debug ("%s hwirq[%ld]: address_hi[%#x], address_lo[%#x], data[%#x]\n" , + __func__, data->hwirq, msg->address_hi, msg->address_lo, msg->data); +} + +static 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 irq_fwspec fwspec; +struct irq_data *d; +int ret; + + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count =2 ; + fwspec.param[0 ] = 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_data *priv = domain->host_data; +int hwirq, err, i; + + hwirq =sg2042_msi_allocate_hwirq (priv, 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; + +pr_debug ("%s: virq[%d], hwirq[%d]\n" , __func__, virq + i, hwirq + i); + +irq_domain_set_hwirq_and_chip (domain, virq + i, hwirq + i, + &sg2042_msi_middle_irq_chip, priv); + } + +return 0 ; + +err_hwirq: +sg2042_msi_free_hwirq (priv, 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_data *priv =irq_data_get_irq_chip_data (d); + +irq_domain_free_irqs_parent (domain, virq, nr_irqs); +sg2042_msi_free_hwirq (priv, 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 = { + .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_data *priv, +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 , priv->num_irqs, + fwnode, + &sg2042_msi_middle_domain_ops, + priv); +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 of_phandle_args args = {}; +struct sg2042_msi_data *data; +int ret; + + data =devm_kzalloc (&pdev->dev,sizeof (struct sg2042_msi_data ),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); + } + +if (of_property_read_u64 (pdev->dev.of_node,"sophgo,msi-doorbell-addr" , + &data->doorbell_addr)) { +dev_err (&pdev->dev,"Unable to parse MSI doorbell addr\n" ); +return -EINVAL ; + } + + 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" ); +return ret; + } + +if (data->irq_first <SG2042_VECTOR_MIN || + (data->irq_first + data->num_irqs -1 ) >SG2042_VECTOR_MAX ) { +dev_err (&pdev->dev,"msi-ranges is incorrect!\n" ); +return -EINVAL ; + } + +mutex_init (&data->msi_map_lock); + + data->msi_map =bitmap_zalloc (data->num_irqs,GFP_KERNEL ); +if (!data->msi_map) +return -ENOMEM ; + + ret =sg2042_msi_init_domains (data, pdev->dev.of_node); +if (ret) +bitmap_free (data->msi_map); + +return ret; +} + +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 =of_match_ptr (sg2042_msi_of_match), + }, + .probe = sg2042_msi_probe, +}; +builtin_platform_driver (sg2042_msi_driver);
Re: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
Quoted 1 line · Samuel Holland
On 2024-12-09 1:12 AM, Chen Wang wrote:
[......]
Quoted 14 lines
drivers/irqchip/irq-sg2042-msi.c line 47
Quoted 9 lines
drivers/irqchip/irq-sg2042-msi.c new file +9
-0+ +static int sg2042_msi_allocate_hwirq (struct sg2042_msi_data *priv,int num_req) +{ +int first; + +guard (mutex)(&priv->msi_map_lock); + first =bitmap_find_free_region (priv->msi_map, priv->num_irqs, +get_count_order (num_req)); +return first >=0 ? priv->irq_first + first : -ENOSPC ;How does this work? The irqdomain is instantiated with size ==
priv->num_irqs, so hwirqs must be less thanpriv->num_irqs. It also quite simplifies the code for hwirq be a number between 0 andpriv->num_irqs. You only need to apply the offset when allocating the parent IRQ:
Quoted 1 line
fwspec.param[0] = priv->irq_first + hwirq;
I will double check, seems this need to be improved.
Thanks,
Chen
[......]
Re: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
In reply to Chen WangLe 09/12/2024 à 08:12, Chen Wang a écrit :
Quoted 5 lines
From: Chen Wang <[email protected]>
Add driver for Sophgo SG2042 MSI interrupt controller.
Signed-off-by Chen Wang <[email protected]>
...
Quoted 2 lines
drivers/irqchip/irq-sg2042-msi.c new file +2
-0+#define SG2042_VECTOR_MIN 64 +#define SG2042_VECTOR_MAX 95
...
Quoted 1 line
+static struct
irq_chipsg2042_msi_middle_irq_chip= {
const?
Quoted 9 lines
drivers/irqchip/irq-sg2042-msi.c new file +9
-0+ .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, +};
...
Quoted 36 lines
drivers/irqchip/irq-sg2042-msi.c new file +36
-0+static int sg2042_msi_probe (struct platform_device *pdev) +{ +struct of_phandle_args args = {}; +struct sg2042_msi_data *data; +int ret; + + data =devm_kzalloc (&pdev->dev,sizeof (struct sg2042_msi_data ),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); + } + +if (of_property_read_u64 (pdev->dev.of_node,"sophgo,msi-doorbell-addr" , + &data->doorbell_addr)) { +dev_err (&pdev->dev,"Unable to parse MSI doorbell addr\n" ); +return -EINVAL ; + } + + 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" ); +return ret; + }
drivers/irqchip/irq-sg2042-msi.c line 262
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+ +if (data->irq_first <SG2042_VECTOR_MIN || + (data->irq_first + data->num_irqs -1 ) >SG2042_VECTOR_MAX ) { +dev_err (&pdev->dev,"msi-ranges is incorrect!\n" ); +return -EINVAL ; + } + +mutex_init (&data->msi_map_lock); + + data->msi_map =bitmap_zalloc (data->num_irqs,GFP_KERNEL );
IIUC, num_irqs is between 0 and (SG2042_VECTOR_MAX - SG2042_VECTOR_MIN) (maybe + or -1). So around 32.
Would it make sence to use DECLARE_BITMAP(msi_map, <correct_size>) in sg2042_msi_data to avoid this allocation and an indirection at runtime?
drivers/irqchip/irq-sg2042-msi.c line 271
Quoted 9 lines
drivers/irqchip/irq-sg2042-msi.c new file +9
-0+if (!data->msi_map) +return -ENOMEM ; + + ret =sg2042_msi_init_domains (data, pdev->dev.of_node); +if (ret) +bitmap_free (data->msi_map); + +return ret; +}
...
CJ
_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv
Re: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
Quoted 9 lines · Christophe JAILLET
Le 09/12/2024 à 08:12, Chen Wang a écrit :
Quoted 5 lines
From: Chen Wang <[email protected]>
Add driver for Sophgo SG2042 MSI interrupt controller.
Signed-off-by Chen Wang <[email protected]>...
Quoted 8 lines
Quoted 2 lines
drivers/irqchip/irq-sg2042-msi.c new file +2
-0+#define SG2042_VECTOR_MIN 64 +#define SG2042_VECTOR_MAX 95...
Quoted 1 line
+static struct
irq_chipsg2042_msi_middle_irq_chip= {const?
Yes, I will add this in next version, thanks.
Quoted 65 lines
Quoted 10 lines
+ .name = "SG2042 MSI",
+ .irq_ack =sg2042_msi_irq_ack,
+ .irq_mask =irq_chip_mask_parent,
+ .irq_unmask =irq_chip_unmask_parent,drivers/irqchip/irq-sg2042-msi.c new file +5
-0+#ifdef CONFIG_SMP + .irq_set_affinity = irq_chip_set_affinity_parent, +#endif + .irq_compose_msi_msg = sg2042_msi_irq_compose_msi_msg, +};...
Quoted 38 lines
drivers/irqchip/irq-sg2042-msi.c new file +7
-0+static int sg2042_msi_probe (struct platform_device *pdev) +{ + struct of_phandle_args args = {}; + struct sg2042_msi_data *data; + int ret; + + data = devm_kzalloc(&pdev->dev, sizeof(struct sg2042_msi_data),
GFP_KERNEL);
+ if (!data)
+ return-ENOMEM;drivers/irqchip/irq-sg2042-msi.c new file +8
-0+ + 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); + } + + if (of_property_read_u64(pdev->dev.of_node,"sophgo,msi-doorbell-addr",
+&data->doorbell_addr)) {
+dev_err(&pdev->dev, "Unable to parse MSI doorbell addr\n"); + return-EINVAL;
+ }drivers/irqchip/irq-sg2042-msi.c new file +15
-0+ + 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"); + return ret; + }drivers/irqchip/irq-sg2042-msi.c line 262
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+ + if (data->irq_first < SG2042_VECTOR_MIN || + (data->irq_first + data->num_irqs - 1) > SG2042_VECTOR_MAX) { + dev_err(&pdev->dev, "msi-ranges is incorrect!\n"); + return -EINVAL; + } + + mutex_init(&data->msi_map_lock); + + data->msi_map = bitmap_zalloc(data->num_irqs, GFP_KERNEL);IIUC,
num_irqsis between 0 and (SG2042_VECTOR_MAX-SG2042_VECTOR_MIN) (maybe + or -1). So around 32.
Quoted 1 line
Would it make sence to use
DECLARE_BITMAP(msi_map, <correct_size>)insg2042_msi_datato avoid this allocation and an indirection at runtime?
This is also a good choice. I will double check this.
Thanks,
Chen
Quoted 14 lines
drivers/irqchip/irq-sg2042-msi.c line 271
Quoted 10 lines
+ if (!data->msi_map)
+ return-ENOMEM;drivers/irqchip/irq-sg2042-msi.c new file +7
-0+ + ret = sg2042_msi_init_domains(data, pdev->dev.of_node); + if (ret) + bitmap_free(data->msi_map); + + return ret; +}...
CJ
Inochi Amaoto
maintainerRe: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
In reply to Chen WangQuoted 69 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 | 285 +++++++++++++++++++++++++++++++ 3 files changed, 298 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 +18
-0@@ -0,0 +1,285 @@ +// 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>
drivers/irqchip/irq-sg2042-msi.c line 28
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +10
-0+#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "irq-msi-lib.h" + +#define SG2042_VECTOR_MIN 64 +#define SG2042_VECTOR_MAX 95 + +struct sg2042_msi_data {
suggestions: sg2042_msi_chipdata
Quoted 35 lines
drivers/irqchip/irq-sg2042-msi.c new file +35
-0+void __iomem *reg_clr;// clear reg, see TRM, 10.1.33, GP_INTR0_CLR + +u64 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 + +unsigned long *msi_map; +struct mutex msi_map_lock;// lock for msi_map +}; + +static int sg2042_msi_allocate_hwirq (struct sg2042_msi_data *priv,int num_req) +{ +int first; + +guard (mutex)(&priv->msi_map_lock); + first =bitmap_find_free_region (priv->msi_map, priv->num_irqs, +get_count_order (num_req)); +return first >=0 ? priv->irq_first + first : -ENOSPC ; +} + +static void sg2042_msi_free_hwirq (struct sg2042_msi_data *priv, +int hwirq,int num_req) +{ +int first = hwirq - priv->irq_first; + +guard (mutex)(&priv->msi_map_lock); +bitmap_release_region (priv->msi_map, first,get_count_order (num_req)); +} + +static void sg2042_msi_irq_ack (struct irq_data *d) +{ +struct sg2042_msi_data *data =irq_data_get_irq_chip_data (d); +int bit_off = d->hwirq - data->irq_first; +
drivers/irqchip/irq-sg2042-msi.c line 72
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +9
-0+writel (1 << bit_off, (unsigned int *)data->reg_clr); + +irq_chip_ack_parent (d); +} + +static void sg2042_msi_irq_compose_msi_msg (struct irq_data *data, +struct msi_msg *msg) +{ +struct sg2042_msi_data *priv =irq_data_get_irq_chip_data (data);
It will be better to unify the variable name, it is confused for me.
Quoted 177 lines
drivers/irqchip/irq-sg2042-msi.c new file +177
-0+ + msg->address_hi =upper_32_bits (priv->doorbell_addr); + msg->address_lo =lower_32_bits (priv->doorbell_addr); + msg->data =1 << (data->hwirq - priv->irq_first); + +pr_debug ("%s hwirq[%ld]: address_hi[%#x], address_lo[%#x], data[%#x]\n" , + __func__, data->hwirq, msg->address_hi, msg->address_lo, msg->data); +} + +static 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 irq_fwspec fwspec; +struct irq_data *d; +int ret; + + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count =2 ; + fwspec.param[0 ] = 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_data *priv = domain->host_data; +int hwirq, err, i; + + hwirq =sg2042_msi_allocate_hwirq (priv, 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; + +pr_debug ("%s: virq[%d], hwirq[%d]\n" , __func__, virq + i, hwirq + i); + +irq_domain_set_hwirq_and_chip (domain, virq + i, hwirq + i, + &sg2042_msi_middle_irq_chip, priv); + } + +return 0 ; + +err_hwirq: +sg2042_msi_free_hwirq (priv, 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_data *priv =irq_data_get_irq_chip_data (d); + +irq_domain_free_irqs_parent (domain, virq, nr_irqs); +sg2042_msi_free_hwirq (priv, 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 = { + .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_data *priv, +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 , priv->num_irqs, + fwnode, + &sg2042_msi_middle_domain_ops, + priv); +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 of_phandle_args args = {}; +struct sg2042_msi_data *data; +int ret; + + data =devm_kzalloc (&pdev->dev,sizeof (struct sg2042_msi_data ),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); + } + +if (of_property_read_u64 (pdev->dev.of_node,"sophgo,msi-doorbell-addr" , + &data->doorbell_addr)) { +dev_err (&pdev->dev,"Unable to parse MSI doorbell addr\n" ); +return -EINVAL ; + } + + 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) {
drivers/irqchip/irq-sg2042-msi.c line 258
Quoted 10 lines
drivers/irqchip/irq-sg2042-msi.c new file +9
-0+dev_err (&pdev->dev,"Unable to parse MSI vec number\n" ); +return ret; + } + +if (data->irq_first <SG2042_VECTOR_MIN || + (data->irq_first + data->num_irqs -1 ) >SG2042_VECTOR_MAX ) { +dev_err (&pdev->dev,"msi-ranges is incorrect!\n" ); +return -EINVAL ; + }
This check is fine, but I think it is kind of useless. Take the configuration for devicetree and process it as is, which also makes supporting new platform simple.
Quoted 30 lines
drivers/irqchip/irq-sg2042-msi.c new file +27
-0+ +mutex_init (&data->msi_map_lock); + + data->msi_map =bitmap_zalloc (data->num_irqs,GFP_KERNEL ); +if (!data->msi_map) +return -ENOMEM ; + + ret =sg2042_msi_init_domains (data, pdev->dev.of_node); +if (ret) +bitmap_free (data->msi_map); + +return ret; +} + +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 =of_match_ptr (sg2042_msi_of_match), + }, + .probe = sg2042_msi_probe, +}; +builtin_platform_driver (sg2042_msi_driver);Signature · 1 line
2.34.1
Re: [PATCH v2 2/3] irqchip: Add the Sophgo SG2042 MSI interrupt controller
Quoted 2 lines · Inochi Amaoto
Quoted 1 line · Chen Wang
From: Chen Wang <[email protected]>
[......]
Quoted 3 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ +struct sg2042_msi_data {suggestions:
sg2042_msi_chipdata
ok
[......]
Quoted 5 lines
drivers/irqchip/irq-sg2042-msi.c line 72
Quoted 4 lines
drivers/irqchip/irq-sg2042-msi.c new file +4
-0+static void sg2042_msi_irq_compose_msi_msg (struct irq_data *data, +struct msi_msg *msg) +{ +struct sg2042_msi_data *priv =irq_data_get_irq_chip_data (data);It will be better to unify the variable name, it is confused for me.
ok, I will unify this from "priv" to "data" as other functions.
[......]
Quoted 8 lines
drivers/irqchip/irq-sg2042-msi.c line 258
Quoted 5 lines
drivers/irqchip/irq-sg2042-msi.c new file +5
-0+if (data->irq_first <SG2042_VECTOR_MIN || + (data->irq_first + data->num_irqs -1 ) >SG2042_VECTOR_MAX ) { +dev_err (&pdev->dev,"msi-ranges is incorrect!\n" ); +return -EINVAL ; + }This check is fine, but I think it is kind of useless. Take the configuration for devicetree and process it as is, which also makes supporting new platform simple.
Sure, I will drop this check.
[......]
Thanks,
Chen
PATCH v2 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>; + reg-names = "clr"; + msi-controller; + msi-ranges = <&intc 64 IRQ_TYPE_LEVEL_HIGH 32>; + sophgo,msi-doorbell-addr = <0x00000070 0x30010300>; + interrupt-parent = <&intc>; + }; + rpgate: clock-controller@7030010368 { compatible = "sophgo,sg2042-rpgate"; reg = <0x70 0x30010368 0x0 0x98>;
Signature · 1 line
2.34.1