irqchip: loongson-eiointc: Add DT init support
Subsystems (5)
v4 cover irqchip: loongson-eiointc: Add DT init support
Add EIOINTC irqchip DT support, which is needed for Loongson chips that are DT-based and support EIOINTC, such as the Loongson-2K0500 chip.
---
V4:
- patch(1/2)
- Simplify the definition of the reg attribute by declaring the entire chip configuration space directly.
V3:
- patch(1/2)
- Drop quotes;
- Drop interrupt-names;
- Drop loongson,eio-num-vecs;
- SoC-based compatibles instead of version-based compatibles.
- patch (2/2)
- irq_set_handler_data() is used to get parent irq form DTS;
- Set vec_count by judging compatibles.
V2:
- Add the dt-bindings file (1/2);
- patch(2/2)
- Remove forgotten debugging messages;
- Change compatible string name to "loongson,eiointc-1.0".
Binbin Zhou (2):
dt-bindings: interrupt-controller: Add Loongson EIOINTC irqchip/loongson-eiointc: Add DT init support
.../loongson,eiointc.yaml | 59 ++++++++ drivers/irqchip/irq-loongson-eiointc.c | 129 +++++++++++++----- 2 files changed, 154 insertions(+), 34 deletions(-) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/loongson,eiointc.yaml
Signature · 1 line
2.39.1
PATCH v4 1/2 dt-bindings: interrupt-controller: Add Loongson EIOINTC
Add Loongson Extended I/O Interrupt controller binding with DT schema format using json-schema.
--- .../loongson,eiointc.yaml | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/loongson,eiointc.yaml
Documentation/devicetree/bindings/interrupt-controller/loongson,eiointc.yaml new file +59 -0
@@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/loongson,eiointc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson Extended I/O Interrupt Controller + +maintainers: + - Binbin Zhou <[email protected]> + +description: | + This interrupt controller is found on the Loongson-3 family chips and + Loongson-2K series chips and is used to distribute interrupts directly to + individual cores without forwarding them through the HT's interrupt line. + +allOf: + - $ref: /schemas/interrupt-controller.yaml# + +properties: + compatible: + enum: + - loongson,ls2k0500-eiointc + - loongson,ls2k2000-eiointc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + interrupt-controller: true + + '#interrupt-cells': + const: 1 + +required: + - compatible + - reg + - interrupts + - interrupt-controller + - '#interrupt-cells' + +unevaluatedProperties: false + +examples: + - | + eiointc: interrupt-controller@1fe11600 { + compatible = "loongson,ls2k0500-eiointc"; + reg = <0x1fe10000 0x10000>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpuintc>; + interrupts = <3>; + }; + +...
Signature · 1 line
2.39.1
Re: [PATCH V4 1/2] dt-bindings: interrupt-controller: Add Loongson EIOINTC
Quoted 9 lines · Binbin Zhou
Add Loongson Extended I/O Interrupt controller binding with DT schema format using json-schema.
Signed-off-by Binbin Zhou <[email protected]>--- .../loongson,eiointc.yaml | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/loongson,eiointc.yaml
PATCH v4 2/2 irqchip/loongson-eiointc: Add DT init support
In reply to Binbin ZhouAdd EIOINTC irqchip DT support, which is needed for Loongson chips based on DT and supporting EIOINTC, such as the Loongson-2K0500 SOC.
--- drivers/irqchip/irq-loongson-eiointc.c | 129 ++++++++++++++++++------- 1 file changed, 95 insertions(+), 34 deletions(-)
drivers/irqchip/irq-loongson-eiointc.c +95 -34
@@ -39,6 +39,7 @@ static int nr_pics;struct eiointc_priv {u32 node; +u32 vec_count;nodemask_t node_map;cpumask_t cpuspan_map;struct fwnode_handle *domain_handle;
@@ -156,18 +157,18 @@ static int eiointc_router_init(unsigned int cpu)if ((cpu_logical_map (cpu) %CORES_PER_EIO_NODE ) ==0 ) {eiointc_enable (); -for (i =0 ; i <VEC_COUNT /32 ; i++) { +for (i =0 ; i < eiointc_priv[0 ]->vec_count /32 ; i++) { data = (((1 << (i *2 +1 )) <<16 ) | (1 << (i *2 )));iocsr_write32 (data,EIOINTC_REG_NODEMAP + i *4 ); } -for (i =0 ; i <VEC_COUNT /32 /4 ; i++) { +for (i =0 ; i < eiointc_priv[0 ]->vec_count /32 /4 ; i++) { bit =BIT (1 + index);/* Route to IP[1 + index] */ data = bit | (bit <<8 ) | (bit <<16 ) | (bit <<24 );iocsr_write32 (data,EIOINTC_REG_IPMAP + i *4 ); } -for (i =0 ; i <VEC_COUNT /4 ; i++) { +for (i =0 ; i < eiointc_priv[0 ]->vec_count /4 ; i++) {/* Route to Node-0 Core-0 */ if (index ==0 ) bit =BIT (cpu_logical_map (0 ));
@@ -178,7 +179,7 @@ static int eiointc_router_init(unsigned int cpu)iocsr_write32 (data,EIOINTC_REG_ROUTE + i *4 ); } -for (i =0 ; i <VEC_COUNT /32 ; i++) { +for (i =0 ; i < eiointc_priv[0 ]->vec_count /32 ; i++) { data =0xffffffff ;iocsr_write32 (data,EIOINTC_REG_ENABLE + i *4 );iocsr_write32 (data,EIOINTC_REG_BOUNCE + i *4 );
@@ -198,7 +199,7 @@ static void eiointc_irq_dispatch(struct irq_desc *desc)chained_irq_enter (chip, desc); -for (i =0 ; i <VEC_REG_COUNT ; i++) { +for (i =0 ; i < eiointc_priv[0 ]->vec_count /VEC_COUNT_PER_REG ; i++) { pending =iocsr_read64 (EIOINTC_REG_ISR + (i <<3 ));iocsr_write64 (pending,EIOINTC_REG_ISR + (i <<3 ));while (pending) {
@@ -316,7 +317,7 @@ static void eiointc_resume(void)eiointc_router_init (0 );for (i =0 ; i < nr_pics; i++) { -for (j =0 ; j <VEC_COUNT ; j++) { +for (j =0 ; j < eiointc_priv[0 ]->vec_count; j++) { desc =irq_resolve_mapping (eiointc_priv[i]->eiointc_domain, j);if (desc && desc->handle_irq && desc->handle_irq != handle_bad_irq) {raw_spin_lock (&desc->lock);
@@ -373,11 +374,44 @@ static int __init acpi_cascade_irqdomain_init(void)return 0 ; } +static int __init eiointc_init (struct eiointc_priv *priv,int parent_irq, +u64 node_map) +{ +int i; + + node_map = node_map ? node_map :-1ULL ; +for_each_possible_cpu (i) { +if (node_map & (1ULL << (cpu_to_eio_node (i)))) { +node_set (cpu_to_eio_node (i), priv->node_map); +cpumask_or (&priv->cpuspan_map, &priv->cpuspan_map, +cpumask_of (i)); + } + } + + priv->eiointc_domain =irq_domain_create_linear (priv->domain_handle, + priv->vec_count, + &eiointc_domain_ops, + priv); +if (!priv->eiointc_domain) { +pr_err ("loongson-extioi: cannot add IRQ domain\n" ); +return -ENOMEM ; + } + + eiointc_priv[nr_pics++] = priv; +eiointc_router_init (0 ); +irq_set_chained_handler_and_data (parent_irq, eiointc_irq_dispatch, priv); +register_syscore_ops (&eiointc_syscore_ops); +cpuhp_setup_state_nocalls (CPUHP_AP_IRQ_LOONGARCH_STARTING , +"irqchip/loongarch/intc:starting" , + eiointc_router_init,NULL ); + +return 0 ; +} +int __init eiointc_acpi_init (struct irq_domain *parent,struct acpi_madt_eio_pic *acpi_eiointc) { -int i, ret, parent_irq; -unsigned long node_map; +int parent_irq, ret;struct eiointc_priv *priv; priv =kzalloc (sizeof (*priv),GFP_KERNEL );
@@ -391,39 +425,20 @@ int __init eiointc_acpi_init(struct irq_domain *parent, goto out_free_priv; } + priv->vec_count =VEC_COUNT ; priv->node = acpi_eiointc->node; - node_map = acpi_eiointc->node_map ? :-1ULL ; - -for_each_possible_cpu (i) { -if (node_map & (1ULL <<cpu_to_eio_node (i))) { -node_set (cpu_to_eio_node (i), priv->node_map); -cpumask_or (&priv->cpuspan_map, &priv->cpuspan_map,cpumask_of (i)); - } - } - -/* Setup IRQ domain */ - priv->eiointc_domain =irq_domain_create_linear (priv->domain_handle,VEC_COUNT , - &eiointc_domain_ops, priv); -if (!priv->eiointc_domain) { -pr_err ("loongson-eiointc: cannot add IRQ domain\n" ); - goto out_free_handle; - } - - eiointc_priv[nr_pics++] = priv; - -eiointc_router_init (0 ); - parent_irq =irq_create_mapping (parent, acpi_eiointc->cascade); -irq_set_chained_handler_and_data (parent_irq, eiointc_irq_dispatch, priv); -register_syscore_ops (&eiointc_syscore_ops); -cpuhp_setup_state_nocalls (CPUHP_AP_IRQ_LOONGARCH_STARTING , -"irqchip/loongarch/intc:starting" , - eiointc_router_init,NULL ); + ret =eiointc_init (priv, parent_irq, acpi_eiointc->node_map); +if (ret <0 ) + goto out_free_handle;acpi_set_vec_parent (acpi_eiointc->node, priv->eiointc_domain, pch_group);acpi_set_vec_parent (acpi_eiointc->node, priv->eiointc_domain, msi_group); + ret =acpi_cascade_irqdomain_init (); +if (ret <0 ) + goto out_free_handle;return ret;
@@ -435,3 +450,49 @@ int __init eiointc_acpi_init(struct irq_domain *parent,return -ENOMEM ; } + +static int __init eiointc_of_init (struct device_node *of_node, +struct device_node *parent) +{ +int parent_irq, ret; +struct eiointc_priv *priv; + + priv =kzalloc (sizeof (*priv),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + + parent_irq =irq_of_parse_and_map (of_node,0 ); +if (parent_irq <=0 ) { + ret = -ENODEV ; + goto out_free_priv; + } + + ret =irq_set_handler_data (parent_irq, priv); +if (ret <0 ) + goto out_free_priv; + +/* +* In particular, the number of devices supported by the LS2K0500 +* extended I/O interrupt vector is 128. +*/ +if (of_device_is_compatible (of_node,"loongson,ls2k0500-eiointc" )) + priv->vec_count =128 ; +else + priv->vec_count =VEC_COUNT ; + + priv->node =0 ; + priv->domain_handle =of_node_to_fwnode (of_node); + + ret =eiointc_init (priv, parent_irq,0 ); +if (ret <0 ) + goto out_free_priv; + +return 0 ; + +out_free_priv: +kfree (priv); +return ret; +} + +IRQCHIP_DECLARE (loongson_ls2k0500_eiointc,"loongson,ls2k0500-eiointc" , eiointc_of_init); +IRQCHIP_DECLARE (loongson_ls2k2000_eiointc,"loongson,ls2k2000-eiointc" , eiointc_of_init);
Signature · 1 line
2.39.1