2019-01-26 15:41:22

by Zhou Yanjie

[permalink] [raw]
Subject: Add Ingenic X1000 irqchip support.

Add Ingenic X1000 irqchip support.




2019-01-26 15:41:57

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 1/4] Irqchip: Ingenic: Change interrupt handling form cascade to chained_irq.

The interrupt handling method is changed from old-style cascade to
chained_irq which is more appropriate. Also, it can process the
corner situation that more than one irq is coming to a single
chip at the same time.

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 49 ++++++++++++++++++++++---------------------
1 file changed, 25 insertions(+), 24 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 2ff0898..2713ec4 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <[email protected]>
- * JZ4740 platform IRQ support
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
+ * Ingenic XBurst platform IRQ support
*/

#include <linux/errno.h>
@@ -19,6 +10,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/ingenic.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -41,22 +33,35 @@ struct ingenic_intc_data {
#define JZ_REG_INTC_PENDING 0x10
#define CHIP_SIZE 0x20

-static irqreturn_t intc_cascade(int irq, void *data)
+static void ingenic_chained_handle_irq(struct irq_desc *desc)
{
- struct ingenic_intc_data *intc = irq_get_handler_data(irq);
- uint32_t irq_reg;
+ struct ingenic_intc_data *intc = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ bool have_irq = false;
+ u32 pending;
unsigned i;

+ chained_irq_enter(chip, desc);
for (i = 0; i < intc->num_chips; i++) {
- irq_reg = readl(intc->base + (i * CHIP_SIZE) +
+ pending = readl(intc->base + (i * CHIP_SIZE) +
JZ_REG_INTC_PENDING);
- if (!irq_reg)
+ if (!pending)
continue;

- generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE);
+ have_irq = true;
+ while (pending) {
+ int bit = __ffs(pending);
+
+ generic_handle_irq(__fls(pending) + (i * 32) +
+ JZ4740_IRQ_BASE);
+ pending &= ~BIT(bit);
+ }
}

- return IRQ_HANDLED;
+ if (!have_irq)
+ spurious_interrupt();
+
+ chained_irq_exit(chip, desc);
}

static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
@@ -79,11 +84,6 @@ void ingenic_intc_irq_resume(struct irq_data *data)
intc_irq_set_mask(gc, gc->mask_cache);
}

-static struct irqaction intc_cascade_action = {
- .handler = intc_cascade,
- .name = "SoC intc cascade interrupt",
-};
-
static int __init ingenic_intc_of_init(struct device_node *node,
unsigned num_chips)
{
@@ -148,7 +148,8 @@ static int __init ingenic_intc_of_init(struct device_node *node,
if (!domain)
pr_warn("unable to register IRQ domain\n");

- setup_irq(parent_irq, &intc_cascade_action);
+ irq_set_chained_handler_and_data(parent_irq,
+ ingenic_chained_handle_irq, intc);
return 0;

out_unmap_irq:
--
2.7.4



2019-01-26 15:42:18

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 2/4] Irqchip: Ingenic: Unify the function name prefix to "ingenic_intc_".

For the sake of uniform style, function "intc_irq_set_mask" is
changed to "ingenic_intc_intc_irq_set_mask".

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 2713ec4..69be219 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -64,7 +64,8 @@ static void ingenic_chained_handle_irq(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}

-static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
+static void ingenic_intc_irq_set_mask(struct irq_chip_generic *gc,
+ uint32_t mask)
{
struct irq_chip_regs *regs = &gc->chip_types->regs;

@@ -75,13 +76,13 @@ static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
void ingenic_intc_irq_suspend(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- intc_irq_set_mask(gc, gc->wake_active);
+ ingenic_intc_irq_set_mask(gc, gc->wake_active);
}

void ingenic_intc_irq_resume(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- intc_irq_set_mask(gc, gc->mask_cache);
+ ingenic_intc_irq_set_mask(gc, gc->mask_cache);
}

static int __init ingenic_intc_of_init(struct device_node *node,
--
2.7.4



2019-01-26 15:43:57

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 4/4] Irqchip: Ingenic: Add support for the X1000.

Add support for probing the irq-ingenic driver on the X1000 Soc.
X1000 is a 1.0GHz processor for IoT. It has MIPS32 XBurst RISC core
with double precision hardware float point unit.

Signed-off-by: Zhou Yanjie <[email protected]>
---
Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt | 1 +
1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
index d4373d0..fa69b3f 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
@@ -8,6 +8,7 @@ Required properties:
ingenic,jz4770-intc
ingenic,jz4775-intc
ingenic,jz4780-intc
+ ingenic,x1000-intc
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
--
2.7.4



2019-01-26 15:44:17

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 3/4] Irqchip: Ingenic: Add support for the X1000.

Add support for probing the irq-ingenic driver on the X1000 Soc.
X1000 is a 1.0GHz processor for IoT. It has MIPS32 XBurst RISC core
with double precision hardware float point unit.

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 69be219..0b643c7 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -177,3 +177,4 @@ static int __init intc_2chip_of_init(struct device_node *node,
IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init);
+IRQCHIP_DECLARE(x1000_intc, "ingenic,x1000-intc", intc_2chip_of_init);
--
2.7.4



2019-01-27 10:15:29

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH 3/4] Irqchip: Ingenic: Add support for the X1000.

On Sat, 26 Jan 2019 15:38:42 +0000,
Zhou Yanjie <[email protected]> wrote:
>
> Add support for probing the irq-ingenic driver on the X1000 Soc.
> X1000 is a 1.0GHz processor for IoT. It has MIPS32 XBurst RISC core
> with double precision hardware float point unit.

I don't think we need the marketing spiel, as none of the advertised
target market, ISA or feature set of this SoC is relevant for this
patch. Put it in the cover letter if you must.

Instead, explaining that it behaves just like any of the other "2chip"
Ingenic SoCs makes is much more relevant.

>
> Signed-off-by: Zhou Yanjie <[email protected]>
> ---
> drivers/irqchip/irq-ingenic.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
> index 69be219..0b643c7 100644
> --- a/drivers/irqchip/irq-ingenic.c
> +++ b/drivers/irqchip/irq-ingenic.c
> @@ -177,3 +177,4 @@ static int __init intc_2chip_of_init(struct device_node *node,
> IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init);
> IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init);
> IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init);
> +IRQCHIP_DECLARE(x1000_intc, "ingenic,x1000-intc", intc_2chip_of_init);
> --
> 2.7.4
>
>

Thanks,

M.

--
Jazz is not dead, it just smell funny.

2019-01-27 10:23:36

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH 1/4] Irqchip: Ingenic: Change interrupt handling form cascade to chained_irq.

On Sat, 26 Jan 2019 15:38:40 +0000,
Zhou Yanjie <[email protected]> wrote:
>
> The interrupt handling method is changed from old-style cascade to
> chained_irq which is more appropriate. Also, it can process the
> corner situation that more than one irq is coming to a single
> chip at the same time.
>
> Signed-off-by: Zhou Yanjie <[email protected]>
> ---
> drivers/irqchip/irq-ingenic.c | 49 ++++++++++++++++++++++---------------------
> 1 file changed, 25 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
> index 2ff0898..2713ec4 100644
> --- a/drivers/irqchip/irq-ingenic.c
> +++ b/drivers/irqchip/irq-ingenic.c
> @@ -1,16 +1,7 @@
> +// SPDX-License-Identifier: GPL-2.0
> /*
> * Copyright (C) 2009-2010, Lars-Peter Clausen <[email protected]>
> - * JZ4740 platform IRQ support
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms of the GNU General Public License as published by the
> - * Free Software Foundation; either version 2 of the License, or (at your
> - * option) any later version.
> - *
> - * You should have received a copy of the GNU General Public License along
> - * with this program; if not, write to the Free Software Foundation, Inc.,
> - * 675 Mass Ave, Cambridge, MA 02139, USA.
> - *
> + * Ingenic XBurst platform IRQ support
> */
>
> #include <linux/errno.h>
> @@ -19,6 +10,7 @@
> #include <linux/interrupt.h>
> #include <linux/ioport.h>
> #include <linux/irqchip.h>
> +#include <linux/irqchip/chained_irq.h>
> #include <linux/irqchip/ingenic.h>
> #include <linux/of_address.h>
> #include <linux/of_irq.h>
> @@ -41,22 +33,35 @@ struct ingenic_intc_data {
> #define JZ_REG_INTC_PENDING 0x10
> #define CHIP_SIZE 0x20
>
> -static irqreturn_t intc_cascade(int irq, void *data)
> +static void ingenic_chained_handle_irq(struct irq_desc *desc)
> {
> - struct ingenic_intc_data *intc = irq_get_handler_data(irq);
> - uint32_t irq_reg;
> + struct ingenic_intc_data *intc = irq_desc_get_handler_data(desc);
> + struct irq_chip *chip = irq_desc_get_chip(desc);
> + bool have_irq = false;
> + u32 pending;
> unsigned i;
>
> + chained_irq_enter(chip, desc);
> for (i = 0; i < intc->num_chips; i++) {
> - irq_reg = readl(intc->base + (i * CHIP_SIZE) +
> + pending = readl(intc->base + (i * CHIP_SIZE) +
> JZ_REG_INTC_PENDING);
> - if (!irq_reg)
> + if (!pending)
> continue;
>
> - generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE);
> + have_irq = true;
> + while (pending) {
> + int bit = __ffs(pending);

So 'bit' is the least significant bit in the pending word,

> +
> + generic_handle_irq(__fls(pending) + (i * 32) +

and here you handle the *most significant* bit,

> + JZ4740_IRQ_BASE);
> + pending &= ~BIT(bit);

yet it is the least significant bit that you clear. I am tempted to
say that you have never tested this code with more than a single
interrupt.

Thanks,

M.

--
Jazz is not dead, it just smell funny.

2019-01-27 14:52:58

by Zhou Yanjie

[permalink] [raw]
Subject: Re: [PATCH 3/4] Irqchip: Ingenic: Add support for the X1000.

Thanks for your suggestions, It will be deleted in the v2.

On 2019年01月27日 18:14, Marc Zyngier wrote:
> On Sat, 26 Jan 2019 15:38:42 +0000,
> Zhou Yanjie <[email protected]> wrote:
>> Add support for probing the irq-ingenic driver on the X1000 Soc.
>> X1000 is a 1.0GHz processor for IoT. It has MIPS32 XBurst RISC core
>> with double precision hardware float point unit.
> I don't think we need the marketing spiel, as none of the advertised
> target market, ISA or feature set of this SoC is relevant for this
> patch. Put it in the cover letter if you must.
>
> Instead, explaining that it behaves just like any of the other "2chip"
> Ingenic SoCs makes is much more relevant.
>
>> Signed-off-by: Zhou Yanjie <[email protected]>
>> ---
>> drivers/irqchip/irq-ingenic.c | 1 +
>> 1 file changed, 1 insertion(+)
>>
>> diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
>> index 69be219..0b643c7 100644
>> --- a/drivers/irqchip/irq-ingenic.c
>> +++ b/drivers/irqchip/irq-ingenic.c
>> @@ -177,3 +177,4 @@ static int __init intc_2chip_of_init(struct device_node *node,
>> IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init);
>> IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init);
>> IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init);
>> +IRQCHIP_DECLARE(x1000_intc, "ingenic,x1000-intc", intc_2chip_of_init);
>> --
>> 2.7.4
>>
>>
> Thanks,
>
> M.
>




2019-01-27 14:53:32

by Zhou Yanjie

[permalink] [raw]
Subject: Re: [PATCH 1/4] Irqchip: Ingenic: Change interrupt handling form cascade to chained_irq.

My fault, in the function "generic_handle_irq" should use "bit" instead
of "__fls(irq_reg)".
It will be fixed in the v2.

On 2019年01月27日 18:21, Marc Zyngier wrote:
> On Sat, 26 Jan 2019 15:38:40 +0000,
> Zhou Yanjie <[email protected]> wrote:
>> The interrupt handling method is changed from old-style cascade to
>> chained_irq which is more appropriate. Also, it can process the
>> corner situation that more than one irq is coming to a single
>> chip at the same time.
>>
>> Signed-off-by: Zhou Yanjie <[email protected]>
>> ---
>> drivers/irqchip/irq-ingenic.c | 49 ++++++++++++++++++++++---------------------
>> 1 file changed, 25 insertions(+), 24 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
>> index 2ff0898..2713ec4 100644
>> --- a/drivers/irqchip/irq-ingenic.c
>> +++ b/drivers/irqchip/irq-ingenic.c
>> @@ -1,16 +1,7 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> /*
>> * Copyright (C) 2009-2010, Lars-Peter Clausen <[email protected]>
>> - * JZ4740 platform IRQ support
>> - *
>> - * This program is free software; you can redistribute it and/or modify it
>> - * under the terms of the GNU General Public License as published by the
>> - * Free Software Foundation; either version 2 of the License, or (at your
>> - * option) any later version.
>> - *
>> - * You should have received a copy of the GNU General Public License along
>> - * with this program; if not, write to the Free Software Foundation, Inc.,
>> - * 675 Mass Ave, Cambridge, MA 02139, USA.
>> - *
>> + * Ingenic XBurst platform IRQ support
>> */
>>
>> #include <linux/errno.h>
>> @@ -19,6 +10,7 @@
>> #include <linux/interrupt.h>
>> #include <linux/ioport.h>
>> #include <linux/irqchip.h>
>> +#include <linux/irqchip/chained_irq.h>
>> #include <linux/irqchip/ingenic.h>
>> #include <linux/of_address.h>
>> #include <linux/of_irq.h>
>> @@ -41,22 +33,35 @@ struct ingenic_intc_data {
>> #define JZ_REG_INTC_PENDING 0x10
>> #define CHIP_SIZE 0x20
>>
>> -static irqreturn_t intc_cascade(int irq, void *data)
>> +static void ingenic_chained_handle_irq(struct irq_desc *desc)
>> {
>> - struct ingenic_intc_data *intc = irq_get_handler_data(irq);
>> - uint32_t irq_reg;
>> + struct ingenic_intc_data *intc = irq_desc_get_handler_data(desc);
>> + struct irq_chip *chip = irq_desc_get_chip(desc);
>> + bool have_irq = false;
>> + u32 pending;
>> unsigned i;
>>
>> + chained_irq_enter(chip, desc);
>> for (i = 0; i < intc->num_chips; i++) {
>> - irq_reg = readl(intc->base + (i * CHIP_SIZE) +
>> + pending = readl(intc->base + (i * CHIP_SIZE) +
>> JZ_REG_INTC_PENDING);
>> - if (!irq_reg)
>> + if (!pending)
>> continue;
>>
>> - generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE);
>> + have_irq = true;
>> + while (pending) {
>> + int bit = __ffs(pending);
> So 'bit' is the least significant bit in the pending word,
>
>> +
>> + generic_handle_irq(__fls(pending) + (i * 32) +
> and here you handle the *most significant* bit,
>
>> + JZ4740_IRQ_BASE);
>> + pending &= ~BIT(bit);
> yet it is the least significant bit that you clear. I am tempted to
> say that you have never tested this code with more than a single
> interrupt.
>
> Thanks,
>
> M.
>




2019-01-27 15:53:22

by Zhou Yanjie

[permalink] [raw]
Subject: Add Ingenic X1000 irqchip support v2.

vi->v2: Replace "__fls(pending)" with "bit" in function "generic_handle_irq".



2019-01-27 15:53:45

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH v2 1/4] Irqchip: Ingenic: Change interrupt handling form cascade to chained_irq.

The interrupt handling method is changed from old-style cascade to
chained_irq which is more appropriate. Also, it can process the
corner situation that more than one irq is coming to a single
chip at the same time.

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 48 +++++++++++++++++++++----------------------
1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 2ff0898..5f775a1 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <[email protected]>
- * JZ4740 platform IRQ support
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
+ * Ingenic XBurst platform IRQ support
*/

#include <linux/errno.h>
@@ -19,6 +10,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/ingenic.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -41,22 +33,34 @@ struct ingenic_intc_data {
#define JZ_REG_INTC_PENDING 0x10
#define CHIP_SIZE 0x20

-static irqreturn_t intc_cascade(int irq, void *data)
+static void ingenic_chained_handle_irq(struct irq_desc *desc)
{
- struct ingenic_intc_data *intc = irq_get_handler_data(irq);
- uint32_t irq_reg;
+ struct ingenic_intc_data *intc = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ bool have_irq = false;
+ uint32_t pending;
unsigned i;

+ chained_irq_enter(chip, desc);
for (i = 0; i < intc->num_chips; i++) {
- irq_reg = readl(intc->base + (i * CHIP_SIZE) +
+ pending = readl(intc->base + (i * CHIP_SIZE) +
JZ_REG_INTC_PENDING);
- if (!irq_reg)
+ if (!pending)
continue;

- generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE);
+ have_irq = true;
+ while (pending) {
+ int bit = __fls(pending);
+
+ generic_handle_irq(bit + (i * 32) + JZ4740_IRQ_BASE);
+ pending &= ~BIT(bit);
+ }
}

- return IRQ_HANDLED;
+ if (!have_irq)
+ spurious_interrupt();
+
+ chained_irq_exit(chip, desc);
}

static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
@@ -79,11 +83,6 @@ void ingenic_intc_irq_resume(struct irq_data *data)
intc_irq_set_mask(gc, gc->mask_cache);
}

-static struct irqaction intc_cascade_action = {
- .handler = intc_cascade,
- .name = "SoC intc cascade interrupt",
-};
-
static int __init ingenic_intc_of_init(struct device_node *node,
unsigned num_chips)
{
@@ -148,7 +147,8 @@ static int __init ingenic_intc_of_init(struct device_node *node,
if (!domain)
pr_warn("unable to register IRQ domain\n");

- setup_irq(parent_irq, &intc_cascade_action);
+ irq_set_chained_handler_and_data(parent_irq,
+ ingenic_chained_handle_irq, intc);
return 0;

out_unmap_irq:
--
2.7.4



2019-01-27 15:54:22

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH v2 2/4] Irqchip: Ingenic: Unify the function name prefix to "ingenic_intc_".

For the sake of uniform style, function "intc_irq_set_mask" is
changed to "ingenic_intc_intc_irq_set_mask".

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 5f775a1..32d090a 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -63,7 +63,8 @@ static void ingenic_chained_handle_irq(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}

-static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
+static void ingenic_intc_irq_set_mask(struct irq_chip_generic *gc,
+ uint32_t mask)
{
struct irq_chip_regs *regs = &gc->chip_types->regs;

@@ -74,13 +75,13 @@ static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
void ingenic_intc_irq_suspend(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- intc_irq_set_mask(gc, gc->wake_active);
+ ingenic_intc_irq_set_mask(gc, gc->wake_active);
}

void ingenic_intc_irq_resume(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- intc_irq_set_mask(gc, gc->mask_cache);
+ ingenic_intc_irq_set_mask(gc, gc->mask_cache);
}

static int __init ingenic_intc_of_init(struct device_node *node,
--
2.7.4



2019-01-27 15:54:57

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH v2 3/4] Irqchip: Ingenic: Add support for the X1000.

Add support for probing the irq-ingenic driver on the X1000 Soc.

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 32d090a..814c68c 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -176,3 +176,4 @@ static int __init intc_2chip_of_init(struct device_node *node,
IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init);
+IRQCHIP_DECLARE(x1000_intc, "ingenic,x1000-intc", intc_2chip_of_init);
--
2.7.4



2019-01-27 15:56:00

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH v2 4/4] Irqchip: Ingenic: Add support for the X1000.

Add support for probing the irq-ingenic driver on the X1000 Soc.

Signed-off-by: Zhou Yanjie <[email protected]>
---
Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt | 1 +
1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
index d4373d0..fa69b3f 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
@@ -8,6 +8,7 @@ Required properties:
ingenic,jz4770-intc
ingenic,jz4775-intc
ingenic,jz4780-intc
+ ingenic,x1000-intc
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
--
2.7.4



2019-01-30 19:44:06

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v2 4/4] Irqchip: Ingenic: Add support for the X1000.

On Sun, 27 Jan 2019 23:50:32 +0800, Zhou Yanjie wrote:
> Add support for probing the irq-ingenic driver on the X1000 Soc.
>
> Signed-off-by: Zhou Yanjie <[email protected]>
> ---
> Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt | 1 +
> 1 file changed, 1 insertion(+)
>

Reviewed-by: Rob Herring <[email protected]>

2019-07-15 12:12:33

by Zhou Yanjie

[permalink] [raw]
Subject: Add Ingenic JZ4760 and X1000 and X1500 irqchip support v3.

v1->v2: Replace "__fls(pending)" with "bit" in function "generic_handle_irq".
v2->v3: Add support for probing irq-ingenic driver on JZ4760 and X1500 Soc.


2019-07-15 12:13:44

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH v3 5/8] dt-bindings: interrupt-controller: Add X1000 and X1000E bindings.

Add the interrupt-controller bindings for the X1000 Soc and
the X1000E Soc from Ingenic.

Signed-off-by: Zhou Yanjie <[email protected]>
---
Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt | 2 ++
1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
index fa1ad54..4f91bda 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
@@ -10,6 +10,8 @@ Required properties:
ingenic,jz4770-intc
ingenic,jz4775-intc
ingenic,jz4780-intc
+ ingenic,x1000-intc
+ ingenic,x1000e-intc
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
--
2.7.4


2019-07-15 12:13:44

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH v3 3/8] dt-bindings: interrupt-controller: Add JZ4760 and JZ4760B bindings.

Add the interrupt-controller bindings for the JZ4760 Soc and
the JZ4760B Soc from Ingenic.

Signed-off-by: Zhou Yanjie <[email protected]>
---
Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt | 2 ++
1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
index d4373d0..fa1ad54 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
@@ -5,6 +5,8 @@ Required properties:
- compatible : should be "ingenic,<socname>-intc". Valid strings are:
ingenic,jz4740-intc
ingenic,jz4725b-intc
+ ingenic,jz4760-intc
+ ingenic,jz4760b-intc
ingenic,jz4770-intc
ingenic,jz4775-intc
ingenic,jz4780-intc
--
2.7.4


2019-07-15 12:13:48

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH v3 8/8] irqchip: Ingenic: Add support for X1500.

Add support for probing the irq-ingenic driver on the
X1500 Soc from Ingenic.

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index e8f7ae7..b72430c 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -180,3 +180,4 @@ IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(x1000_intc, "ingenic,x1000-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(x1000e_intc, "ingenic,x1000e-intc", intc_2chip_of_init);
+IRQCHIP_DECLARE(x1500_intc, "ingenic,x1500-intc", intc_2chip_of_init);
--
2.7.4


2019-07-15 12:13:49

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH v3 6/8] irqchip: Ingenic: Add support for X1000 and X1000E.

Add support for probing the irq-ingenic driver on the X1000 Soc
and the X1000E Soc from Ingenic.

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index e9e959c..e8f7ae7 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -178,3 +178,5 @@ IRQCHIP_DECLARE(jz4760b_intc, "ingenic,jz4760b-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init);
+IRQCHIP_DECLARE(x1000_intc, "ingenic,x1000-intc", intc_2chip_of_init);
+IRQCHIP_DECLARE(x1000e_intc, "ingenic,x1000e-intc", intc_2chip_of_init);
--
2.7.4


2019-07-15 12:14:07

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH v3 7/8] dt-bindings: interrupt-controller: Add X1500 bindings.

Add the interrupt-controller bindings for the
X1500 Soc from Ingenic.

Signed-off-by: Zhou Yanjie <[email protected]>
---
Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt | 1 +
1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
index 4f91bda..a96e120 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
@@ -12,6 +12,7 @@ Required properties:
ingenic,jz4780-intc
ingenic,x1000-intc
ingenic,x1000e-intc
+ ingenic,x1500-intc
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
--
2.7.4


2019-07-26 13:38:17

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH v3 3/8] dt-bindings: interrupt-controller: Add JZ4760 and JZ4760B bindings.

On Mon, 15 Jul 2019 13:09:50 +0100,
Zhou Yanjie <[email protected]> wrote:
>
> Add the interrupt-controller bindings for the JZ4760 Soc and
> the JZ4760B Soc from Ingenic.
>
> Signed-off-by: Zhou Yanjie <[email protected]>
> ---
> Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
> index d4373d0..fa1ad54 100644
> --- a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
> +++ b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
> @@ -5,6 +5,8 @@ Required properties:
> - compatible : should be "ingenic,<socname>-intc". Valid strings are:
> ingenic,jz4740-intc
> ingenic,jz4725b-intc
> + ingenic,jz4760-intc
> + ingenic,jz4760b-intc
> ingenic,jz4770-intc
> ingenic,jz4775-intc
> ingenic,jz4780-intc
> --
> 2.7.4
>
>

This should be combined with patches 5 and 7. I don't see the need for
multiple patches. Same thing should happen with patches 4, 6 and 8.

Thanks,

M.

--
Jazz is not dead, it just smells funny.

2019-07-28 17:35:47

by Zhou Yanjie

[permalink] [raw]
Subject: Add Ingenic JZ4760 and X1000 and X1500 irqchip support v4.

v1->v2: Replace "__fls(pending)" with "bit" in function "generic_handle_irq".
v2->v3: Add support for probing irq-ingenic driver on JZ4760 and X1500 Soc.
v3->v4: Combined with patches 5 and 7, combined with patches 4, 6 and 8.



2019-07-28 17:36:07

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 1/4 v4] irqchip: Ingenic: Change interrupt handling form cascade to chained_irq.

The interrupt handling method is changed from old-style cascade to
chained_irq which is more appropriate. Also, it can process the
corner situation that more than one irq is coming to a single
chip at the same time.

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 37 +++++++++++++++++++++++--------------
1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index f126255..49f7685 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <[email protected]>
- * JZ4740 platform IRQ support
+ * Ingenic XBurst platform IRQ support
*/

#include <linux/errno.h>
@@ -10,6 +10,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/ingenic.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -32,22 +33,34 @@ struct ingenic_intc_data {
#define JZ_REG_INTC_PENDING 0x10
#define CHIP_SIZE 0x20

-static irqreturn_t intc_cascade(int irq, void *data)
+static void ingenic_chained_handle_irq(struct irq_desc *desc)
{
- struct ingenic_intc_data *intc = irq_get_handler_data(irq);
- uint32_t irq_reg;
+ struct ingenic_intc_data *intc = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ bool have_irq = false;
+ uint32_t pending;
unsigned i;

+ chained_irq_enter(chip, desc);
for (i = 0; i < intc->num_chips; i++) {
- irq_reg = readl(intc->base + (i * CHIP_SIZE) +
+ pending = readl(intc->base + (i * CHIP_SIZE) +
JZ_REG_INTC_PENDING);
- if (!irq_reg)
+ if (!pending)
continue;

- generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE);
+ have_irq = true;
+ while (pending) {
+ int bit = __fls(pending);
+
+ generic_handle_irq(bit + (i * 32) + JZ4740_IRQ_BASE);
+ pending &= ~BIT(bit);
+ }
}

- return IRQ_HANDLED;
+ if (!have_irq)
+ spurious_interrupt();
+
+ chained_irq_exit(chip, desc);
}

static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
@@ -70,11 +83,6 @@ void ingenic_intc_irq_resume(struct irq_data *data)
intc_irq_set_mask(gc, gc->mask_cache);
}

-static struct irqaction intc_cascade_action = {
- .handler = intc_cascade,
- .name = "SoC intc cascade interrupt",
-};
-
static int __init ingenic_intc_of_init(struct device_node *node,
unsigned num_chips)
{
@@ -139,7 +147,8 @@ static int __init ingenic_intc_of_init(struct device_node *node,
if (!domain)
pr_warn("unable to register IRQ domain\n");

- setup_irq(parent_irq, &intc_cascade_action);
+ irq_set_chained_handler_and_data(parent_irq,
+ ingenic_chained_handle_irq, intc);
return 0;

out_unmap_irq:
--
2.7.4



2019-07-28 17:37:30

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 4/4 v4] irqchip: Ingenic: Add support for new Ingenic Socs.

Add support for probing the irq-ingenic driver on the JZ4760/JZ4760B
and the X1000/X1000E and the X1500 Socs from Ingenic.

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 8430f5a..b72430c 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -173,6 +173,11 @@ static int __init intc_2chip_of_init(struct device_node *node,
{
return ingenic_intc_of_init(node, 2);
}
+IRQCHIP_DECLARE(jz4760_intc, "ingenic,jz4760-intc", intc_2chip_of_init);
+IRQCHIP_DECLARE(jz4760b_intc, "ingenic,jz4760b-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init);
IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init);
+IRQCHIP_DECLARE(x1000_intc, "ingenic,x1000-intc", intc_2chip_of_init);
+IRQCHIP_DECLARE(x1000e_intc, "ingenic,x1000e-intc", intc_2chip_of_init);
+IRQCHIP_DECLARE(x1500_intc, "ingenic,x1500-intc", intc_2chip_of_init);
--
2.7.4



2019-07-28 17:37:32

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 2/4 v4] irqchip: Ingenic: Unify the function name prefix to "ingenic_intc_".

For the sake of uniform style, function "intc_irq_set_mask" is
changed to "ingenic_intc_intc_irq_set_mask".

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 49f7685..8430f5a 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -63,7 +63,8 @@ static void ingenic_chained_handle_irq(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}

-static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
+static void ingenic_intc_irq_set_mask(struct irq_chip_generic *gc,
+ uint32_t mask)
{
struct irq_chip_regs *regs = &gc->chip_types->regs;

@@ -74,13 +75,13 @@ static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
void ingenic_intc_irq_suspend(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- intc_irq_set_mask(gc, gc->wake_active);
+ ingenic_intc_irq_set_mask(gc, gc->wake_active);
}

void ingenic_intc_irq_resume(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- intc_irq_set_mask(gc, gc->mask_cache);
+ ingenic_intc_irq_set_mask(gc, gc->mask_cache);
}

static int __init ingenic_intc_of_init(struct device_node *node,
--
2.7.4



2019-07-28 17:37:36

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 3/4 v4] dt-bindings: interrupt-controller: Add new Ingenic Socs bindings.

Add the interrupt-controller bindings for the JZ4760/JZ4760B and
the X1000/X1000E and the X1500 Socs from Ingenic.

Signed-off-by: Zhou Yanjie <[email protected]>
---
.../devicetree/bindings/interrupt-controller/ingenic,intc.txt | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
index d4373d0..a96e120 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
@@ -5,9 +5,14 @@ Required properties:
- compatible : should be "ingenic,<socname>-intc". Valid strings are:
ingenic,jz4740-intc
ingenic,jz4725b-intc
+ ingenic,jz4760-intc
+ ingenic,jz4760b-intc
ingenic,jz4770-intc
ingenic,jz4775-intc
ingenic,jz4780-intc
+ ingenic,x1000-intc
+ ingenic,x1000e-intc
+ ingenic,x1500-intc
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
--
2.7.4



2019-07-28 17:40:12

by Zhou Yanjie

[permalink] [raw]
Subject: Re: [PATCH v3 3/8] dt-bindings: interrupt-controller: Add JZ4760 and JZ4760B bindings.

Hi Marc,

These patches has been combined in v4.

Thanks

On 2019年07月26日 21:36, Marc Zyngier wrote:
> On Mon, 15 Jul 2019 13:09:50 +0100,
> Zhou Yanjie <[email protected]> wrote:
>> Add the interrupt-controller bindings for the JZ4760 Soc and
>> the JZ4760B Soc from Ingenic.
>>
>> Signed-off-by: Zhou Yanjie <[email protected]>
>> ---
>> Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt | 2 ++
>> 1 file changed, 2 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
>> index d4373d0..fa1ad54 100644
>> --- a/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
>> +++ b/Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
>> @@ -5,6 +5,8 @@ Required properties:
>> - compatible : should be "ingenic,<socname>-intc". Valid strings are:
>> ingenic,jz4740-intc
>> ingenic,jz4725b-intc
>> + ingenic,jz4760-intc
>> + ingenic,jz4760b-intc
>> ingenic,jz4770-intc
>> ingenic,jz4775-intc
>> ingenic,jz4780-intc
>> --
>> 2.7.4
>>
>>
> This should be combined with patches 5 and 7. I don't see the need for
> multiple patches. Same thing should happen with patches 4, 6 and 8.
>
> Thanks,
>
> M.
>




2019-07-29 22:11:57

by Paul Cercueil

[permalink] [raw]
Subject: Re: [PATCH 1/4 v4] irqchip: Ingenic: Change interrupt handling form cascade to chained_irq.

Hi Zhou,



Le dim. 28 juil. 2019 ? 13:34, Zhou Yanjie <[email protected]> a
?crit :
> The interrupt handling method is changed from old-style cascade to
> chained_irq which is more appropriate. Also, it can process the
> corner situation that more than one irq is coming to a single
> chip at the same time.
>
> Signed-off-by: Zhou Yanjie <[email protected]>
> ---
> drivers/irqchip/irq-ingenic.c | 37
> +++++++++++++++++++++++--------------
> 1 file changed, 23 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/irqchip/irq-ingenic.c
> b/drivers/irqchip/irq-ingenic.c
> index f126255..49f7685 100644
> --- a/drivers/irqchip/irq-ingenic.c
> +++ b/drivers/irqchip/irq-ingenic.c
> @@ -1,7 +1,7 @@
> // SPDX-License-Identifier: GPL-2.0-or-later
> /*
> * Copyright (C) 2009-2010, Lars-Peter Clausen <[email protected]>
> - * JZ4740 platform IRQ support
> + * Ingenic XBurst platform IRQ support
> */
>
> #include <linux/errno.h>
> @@ -10,6 +10,7 @@
> #include <linux/interrupt.h>
> #include <linux/ioport.h>
> #include <linux/irqchip.h>
> +#include <linux/irqchip/chained_irq.h>
> #include <linux/irqchip/ingenic.h>
> #include <linux/of_address.h>
> #include <linux/of_irq.h>
> @@ -32,22 +33,34 @@ struct ingenic_intc_data {
> #define JZ_REG_INTC_PENDING 0x10
> #define CHIP_SIZE 0x20
>
> -static irqreturn_t intc_cascade(int irq, void *data)
> +static void ingenic_chained_handle_irq(struct irq_desc *desc)
> {
> - struct ingenic_intc_data *intc = irq_get_handler_data(irq);
> - uint32_t irq_reg;
> + struct ingenic_intc_data *intc = irq_desc_get_handler_data(desc);
> + struct irq_chip *chip = irq_desc_get_chip(desc);
> + bool have_irq = false;
> + uint32_t pending;
> unsigned i;
>
> + chained_irq_enter(chip, desc);
> for (i = 0; i < intc->num_chips; i++) {
> - irq_reg = readl(intc->base + (i * CHIP_SIZE) +
> + pending = readl(intc->base + (i * CHIP_SIZE) +
> JZ_REG_INTC_PENDING);
> - if (!irq_reg)
> + if (!pending)
> continue;
>
> - generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE);
> + have_irq = true;
> + while (pending) {
> + int bit = __fls(pending);

Use the for_each_set_bit() macro here, that will be simpler.


> +
> + generic_handle_irq(bit + (i * 32) + JZ4740_IRQ_BASE);
> + pending &= ~BIT(bit);
> + }
> }
>
> - return IRQ_HANDLED;
> + if (!have_irq)
> + spurious_interrupt();
> +
> + chained_irq_exit(chip, desc);
> }
>
> static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t
> mask)
> @@ -70,11 +83,6 @@ void ingenic_intc_irq_resume(struct irq_data *data)
> intc_irq_set_mask(gc, gc->mask_cache);
> }
>
> -static struct irqaction intc_cascade_action = {
> - .handler = intc_cascade,
> - .name = "SoC intc cascade interrupt",
> -};
> -
> static int __init ingenic_intc_of_init(struct device_node *node,
> unsigned num_chips)
> {
> @@ -139,7 +147,8 @@ static int __init ingenic_intc_of_init(struct
> device_node *node,
> if (!domain)
> pr_warn("unable to register IRQ domain\n");
>
> - setup_irq(parent_irq, &intc_cascade_action);
> + irq_set_chained_handler_and_data(parent_irq,
> + ingenic_chained_handle_irq, intc);
> return 0;
>
> out_unmap_irq:
> --
> 2.7.4


2019-07-29 22:12:05

by Paul Cercueil

[permalink] [raw]
Subject: Re: [PATCH 4/4 v4] irqchip: Ingenic: Add support for new Ingenic Socs.



Le dim. 28 juil. 2019 ? 13:34, Zhou Yanjie <[email protected]> a
?crit :
> Add support for probing the irq-ingenic driver on the JZ4760/JZ4760B
> and the X1000/X1000E and the X1500 Socs from Ingenic.
>
> Signed-off-by: Zhou Yanjie <[email protected]>
> ---
> drivers/irqchip/irq-ingenic.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/drivers/irqchip/irq-ingenic.c
> b/drivers/irqchip/irq-ingenic.c
> index 8430f5a..b72430c 100644
> --- a/drivers/irqchip/irq-ingenic.c
> +++ b/drivers/irqchip/irq-ingenic.c
> @@ -173,6 +173,11 @@ static int __init intc_2chip_of_init(struct
> device_node *node,
> {
> return ingenic_intc_of_init(node, 2);
> }
> +IRQCHIP_DECLARE(jz4760_intc, "ingenic,jz4760-intc",
> intc_2chip_of_init);
> +IRQCHIP_DECLARE(jz4760b_intc, "ingenic,jz4760b-intc",
> intc_2chip_of_init);
> IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc",
> intc_2chip_of_init);
> IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc",
> intc_2chip_of_init);
> IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc",
> intc_2chip_of_init);
> +IRQCHIP_DECLARE(x1000_intc, "ingenic,x1000-intc",
> intc_2chip_of_init);
> +IRQCHIP_DECLARE(x1000e_intc, "ingenic,x1000e-intc",
> intc_2chip_of_init);
> +IRQCHIP_DECLARE(x1500_intc, "ingenic,x1500-intc",
> intc_2chip_of_init);

All these compatible strings point to the exact same behaviour. It was
already a mistake to have the three "ingenic,jz47[70,75,80]-intc" here;
there should have been only one, e.g. "ingenic,jz4770-intc" and the
other
two SoCs using it as a fallback compatible.

I think you don't need to add these, and in your devicetree just use
"ingenic,jz4780-intc" as a fallback compatible.

Cheers,
-Paul


2019-07-30 11:14:52

by Zhou Yanjie

[permalink] [raw]
Subject: Re: [PATCH 4/4 v4] irqchip: Ingenic: Add support for new Ingenic Socs.

Hi Paul,
It seems very strange to appear another soc model in one soc's devicetree,
and before submitting this patch I referred to some other irq drivers.
Similar
usage was found in irq-sunxi-nmi.c and irq-omap-intc.c, and the original
irq-ingenic.c was declare jz4770, jz4775, jz4780 in the same way. So I
followed
the same method to add the declare of jz4760/x1000/x1500, this may be a
little
better.

On 2019年07月30日 01:25, Paul Cercueil wrote:
>
>
> Le dim. 28 juil. 2019 à 13:34, Zhou Yanjie <[email protected]> a
> écrit :
>> Add support for probing the irq-ingenic driver on the JZ4760/JZ4760B
>> and the X1000/X1000E and the X1500 Socs from Ingenic.
>>
>> Signed-off-by: Zhou Yanjie <[email protected]>
>> ---
>> drivers/irqchip/irq-ingenic.c | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/drivers/irqchip/irq-ingenic.c
>> b/drivers/irqchip/irq-ingenic.c
>> index 8430f5a..b72430c 100644
>> --- a/drivers/irqchip/irq-ingenic.c
>> +++ b/drivers/irqchip/irq-ingenic.c
>> @@ -173,6 +173,11 @@ static int __init intc_2chip_of_init(struct
>> device_node *node,
>> {
>> return ingenic_intc_of_init(node, 2);
>> }
>> +IRQCHIP_DECLARE(jz4760_intc, "ingenic,jz4760-intc",
>> intc_2chip_of_init);
>> +IRQCHIP_DECLARE(jz4760b_intc, "ingenic,jz4760b-intc",
>> intc_2chip_of_init);
>> IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc",
>> intc_2chip_of_init);
>> IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc",
>> intc_2chip_of_init);
>> IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc",
>> intc_2chip_of_init);
>> +IRQCHIP_DECLARE(x1000_intc, "ingenic,x1000-intc", intc_2chip_of_init);
>> +IRQCHIP_DECLARE(x1000e_intc, "ingenic,x1000e-intc",
>> intc_2chip_of_init);
>> +IRQCHIP_DECLARE(x1500_intc, "ingenic,x1500-intc", intc_2chip_of_init);
>
> All these compatible strings point to the exact same behaviour. It was
> already a mistake to have the three "ingenic,jz47[70,75,80]-intc" here;
> there should have been only one, e.g. "ingenic,jz4770-intc" and the other
> two SoCs using it as a fallback compatible.
>
> I think you don't need to add these, and in your devicetree just use
> "ingenic,jz4780-intc" as a fallback compatible.
>
> Cheers,
> -Paul
>
>



2019-07-30 14:12:48

by Zhou Yanjie

[permalink] [raw]
Subject: Re: [PATCH 1/4 v4] irqchip: Ingenic: Change interrupt handling form cascade to chained_irq.

Hi Paul,
Thanks for your suggestion, and after receiving Marc's comments,
if this patch can be continued, I'll use for_each_set_bit() to simplify
code in v5.

On 2019年07月30日 01:19, Paul Cercueil wrote:
> Hi Zhou,
>
>
>
> Le dim. 28 juil. 2019 à 13:34, Zhou Yanjie <[email protected]> a
> écrit :
>> The interrupt handling method is changed from old-style cascade to
>> chained_irq which is more appropriate. Also, it can process the
>> corner situation that more than one irq is coming to a single
>> chip at the same time.
>>
>> Signed-off-by: Zhou Yanjie <[email protected]>
>> ---
>> drivers/irqchip/irq-ingenic.c | 37
>> +++++++++++++++++++++++--------------
>> 1 file changed, 23 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-ingenic.c
>> b/drivers/irqchip/irq-ingenic.c
>> index f126255..49f7685 100644
>> --- a/drivers/irqchip/irq-ingenic.c
>> +++ b/drivers/irqchip/irq-ingenic.c
>> @@ -1,7 +1,7 @@
>> // SPDX-License-Identifier: GPL-2.0-or-later
>> /*
>> * Copyright (C) 2009-2010, Lars-Peter Clausen <[email protected]>
>> - * JZ4740 platform IRQ support
>> + * Ingenic XBurst platform IRQ support
>> */
>>
>> #include <linux/errno.h>
>> @@ -10,6 +10,7 @@
>> #include <linux/interrupt.h>
>> #include <linux/ioport.h>
>> #include <linux/irqchip.h>
>> +#include <linux/irqchip/chained_irq.h>
>> #include <linux/irqchip/ingenic.h>
>> #include <linux/of_address.h>
>> #include <linux/of_irq.h>
>> @@ -32,22 +33,34 @@ struct ingenic_intc_data {
>> #define JZ_REG_INTC_PENDING 0x10
>> #define CHIP_SIZE 0x20
>>
>> -static irqreturn_t intc_cascade(int irq, void *data)
>> +static void ingenic_chained_handle_irq(struct irq_desc *desc)
>> {
>> - struct ingenic_intc_data *intc = irq_get_handler_data(irq);
>> - uint32_t irq_reg;
>> + struct ingenic_intc_data *intc = irq_desc_get_handler_data(desc);
>> + struct irq_chip *chip = irq_desc_get_chip(desc);
>> + bool have_irq = false;
>> + uint32_t pending;
>> unsigned i;
>>
>> + chained_irq_enter(chip, desc);
>> for (i = 0; i < intc->num_chips; i++) {
>> - irq_reg = readl(intc->base + (i * CHIP_SIZE) +
>> + pending = readl(intc->base + (i * CHIP_SIZE) +
>> JZ_REG_INTC_PENDING);
>> - if (!irq_reg)
>> + if (!pending)
>> continue;
>>
>> - generic_handle_irq(__fls(irq_reg) + (i * 32) +
>> JZ4740_IRQ_BASE);
>> + have_irq = true;
>> + while (pending) {
>> + int bit = __fls(pending);
>
> Use the for_each_set_bit() macro here, that will be simpler.
>
>
>> +
>> + generic_handle_irq(bit + (i * 32) + JZ4740_IRQ_BASE);
>> + pending &= ~BIT(bit);
>> + }
>> }
>>
>> - return IRQ_HANDLED;
>> + if (!have_irq)
>> + spurious_interrupt();
>> +
>> + chained_irq_exit(chip, desc);
>> }
>>
>> static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t
>> mask)
>> @@ -70,11 +83,6 @@ void ingenic_intc_irq_resume(struct irq_data *data)
>> intc_irq_set_mask(gc, gc->mask_cache);
>> }
>>
>> -static struct irqaction intc_cascade_action = {
>> - .handler = intc_cascade,
>> - .name = "SoC intc cascade interrupt",
>> -};
>> -
>> static int __init ingenic_intc_of_init(struct device_node *node,
>> unsigned num_chips)
>> {
>> @@ -139,7 +147,8 @@ static int __init ingenic_intc_of_init(struct
>> device_node *node,
>> if (!domain)
>> pr_warn("unable to register IRQ domain\n");
>>
>> - setup_irq(parent_irq, &intc_cascade_action);
>> + irq_set_chained_handler_and_data(parent_irq,
>> + ingenic_chained_handle_irq, intc);
>> return 0;
>>
>> out_unmap_irq:
>> --
>> 2.7.4
>
>



2019-10-02 12:16:21

by Zhou Yanjie

[permalink] [raw]
Subject: Add process for more than one irq at the same time v5

Rebase on top of Paul Cercueil's patches and drop unneeded changes as
Paul Cercueil's advice.


2019-10-02 12:17:38

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 2/5 v5] irqchip: ingenic: Error out if IRQ domain creation failed

From: Paul Cercueil <[email protected]>

If we cannot create the IRQ domain, the driver should fail to probe
instead of succeeding with just a warning message.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 06fa810..d97a3a5 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -87,6 +87,14 @@ static int __init ingenic_intc_of_init(struct device_node *node,
goto out_unmap_irq;
}

+ domain = irq_domain_add_legacy(node, num_chips * 32,
+ JZ4740_IRQ_BASE, 0,
+ &irq_domain_simple_ops, NULL);
+ if (!domain) {
+ err = -ENOMEM;
+ goto out_unmap_base;
+ }
+
for (i = 0; i < num_chips; i++) {
/* Mask all irqs */
writel(0xffffffff, intc->base + (i * CHIP_SIZE) +
@@ -112,14 +120,11 @@ static int __init ingenic_intc_of_init(struct device_node *node,
IRQ_NOPROBE | IRQ_LEVEL);
}

- domain = irq_domain_add_legacy(node, num_chips * 32, JZ4740_IRQ_BASE, 0,
- &irq_domain_simple_ops, NULL);
- if (!domain)
- pr_warn("unable to register IRQ domain\n");
-
setup_irq(parent_irq, &intc_cascade_action);
return 0;

+out_unmap_base:
+ iounmap(intc->base);
out_unmap_irq:
irq_dispose_mapping(parent_irq);
out_free:
--
2.7.4


2019-10-02 12:18:16

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 3/5 v5] irqchip: ingenic: Get virq number from IRQ domain

From: Paul Cercueil <[email protected]>

Get the virq number from the IRQ domain instead of calculating it from
the hardcoded irq base.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index d97a3a5..82a079f 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -21,6 +21,7 @@

struct ingenic_intc_data {
void __iomem *base;
+ struct irq_domain *domain;
unsigned num_chips;
};

@@ -34,6 +35,7 @@ struct ingenic_intc_data {
static irqreturn_t intc_cascade(int irq, void *data)
{
struct ingenic_intc_data *intc = irq_get_handler_data(irq);
+ struct irq_domain *domain = intc->domain;
uint32_t irq_reg;
unsigned i;

@@ -43,7 +45,8 @@ static irqreturn_t intc_cascade(int irq, void *data)
if (!irq_reg)
continue;

- generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE);
+ irq = irq_find_mapping(domain, __fls(irq_reg) + (i * 32));
+ generic_handle_irq(irq);
}

return IRQ_HANDLED;
@@ -95,6 +98,8 @@ static int __init ingenic_intc_of_init(struct device_node *node,
goto out_unmap_base;
}

+ intc->domain = domain;
+
for (i = 0; i < num_chips; i++) {
/* Mask all irqs */
writel(0xffffffff, intc->base + (i * CHIP_SIZE) +
--
2.7.4


2019-10-02 12:18:19

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 1/5 v5] irqchip: ingenic: Drop redundant irq_suspend / irq_resume functions

From: Paul Cercueil <[email protected]>

The same behaviour can be obtained by using the IRQCHIP_MASK_ON_SUSPEND
flag on the IRQ chip.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 24 +-----------------------
include/linux/irqchip/ingenic.h | 14 --------------
2 files changed, 1 insertion(+), 37 deletions(-)
delete mode 100644 include/linux/irqchip/ingenic.h

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index f126255..06fa810 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -10,7 +10,6 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/irqchip.h>
-#include <linux/irqchip/ingenic.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/timex.h>
@@ -50,26 +49,6 @@ static irqreturn_t intc_cascade(int irq, void *data)
return IRQ_HANDLED;
}

-static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
-{
- struct irq_chip_regs *regs = &gc->chip_types->regs;
-
- writel(mask, gc->reg_base + regs->enable);
- writel(~mask, gc->reg_base + regs->disable);
-}
-
-void ingenic_intc_irq_suspend(struct irq_data *data)
-{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- intc_irq_set_mask(gc, gc->wake_active);
-}
-
-void ingenic_intc_irq_resume(struct irq_data *data)
-{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- intc_irq_set_mask(gc, gc->mask_cache);
-}
-
static struct irqaction intc_cascade_action = {
.handler = intc_cascade,
.name = "SoC intc cascade interrupt",
@@ -127,8 +106,7 @@ static int __init ingenic_intc_of_init(struct device_node *node,
ct->chip.irq_mask = irq_gc_mask_disable_reg;
ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
ct->chip.irq_set_wake = irq_gc_set_wake;
- ct->chip.irq_suspend = ingenic_intc_irq_suspend;
- ct->chip.irq_resume = ingenic_intc_irq_resume;
+ ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND;

irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0,
IRQ_NOPROBE | IRQ_LEVEL);
diff --git a/include/linux/irqchip/ingenic.h b/include/linux/irqchip/ingenic.h
deleted file mode 100644
index 1465588..0000000
--- a/include/linux/irqchip/ingenic.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
- */
-
-#ifndef __LINUX_IRQCHIP_INGENIC_H__
-#define __LINUX_IRQCHIP_INGENIC_H__
-
-#include <linux/irq.h>
-
-extern void ingenic_intc_irq_suspend(struct irq_data *data);
-extern void ingenic_intc_irq_resume(struct irq_data *data);
-
-#endif
--
2.7.4


2019-10-02 12:18:44

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 4/5 v5] irqchip: ingenic: Alloc generic chips from IRQ domain

From: Paul Cercueil <[email protected]>

By creating the generic chips from the IRQ domain, we don't rely on the
JZ4740_IRQ_BASE macro. It also makes the code a bit cleaner.

Signed-off-by: Paul Cercueil <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 82a079f..06ab3ad 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -36,12 +36,14 @@ static irqreturn_t intc_cascade(int irq, void *data)
{
struct ingenic_intc_data *intc = irq_get_handler_data(irq);
struct irq_domain *domain = intc->domain;
+ struct irq_chip_generic *gc;
uint32_t irq_reg;
unsigned i;

for (i = 0; i < intc->num_chips; i++) {
- irq_reg = readl(intc->base + (i * CHIP_SIZE) +
- JZ_REG_INTC_PENDING);
+ gc = irq_get_domain_generic_chip(domain, i * 32);
+
+ irq_reg = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
if (!irq_reg)
continue;

@@ -92,7 +94,7 @@ static int __init ingenic_intc_of_init(struct device_node *node,

domain = irq_domain_add_legacy(node, num_chips * 32,
JZ4740_IRQ_BASE, 0,
- &irq_domain_simple_ops, NULL);
+ &irq_generic_chip_ops, NULL);
if (!domain) {
err = -ENOMEM;
goto out_unmap_base;
@@ -100,17 +102,17 @@ static int __init ingenic_intc_of_init(struct device_node *node,

intc->domain = domain;

- for (i = 0; i < num_chips; i++) {
- /* Mask all irqs */
- writel(0xffffffff, intc->base + (i * CHIP_SIZE) +
- JZ_REG_INTC_SET_MASK);
+ err = irq_alloc_domain_generic_chips(domain, 32, 1, "INTC",
+ handle_level_irq, 0,
+ IRQ_NOPROBE | IRQ_LEVEL, 0);
+ if (err)
+ goto out_domain_remove;

- gc = irq_alloc_generic_chip("INTC", 1,
- JZ4740_IRQ_BASE + (i * 32),
- intc->base + (i * CHIP_SIZE),
- handle_level_irq);
+ for (i = 0; i < num_chips; i++) {
+ gc = irq_get_domain_generic_chip(domain, i * 32);

gc->wake_enabled = IRQ_MSK(32);
+ gc->reg_base = intc->base + (i * CHIP_SIZE);

ct = gc->chip_types;
ct->regs.enable = JZ_REG_INTC_CLEAR_MASK;
@@ -121,13 +123,15 @@ static int __init ingenic_intc_of_init(struct device_node *node,
ct->chip.irq_set_wake = irq_gc_set_wake;
ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND;

- irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0,
- IRQ_NOPROBE | IRQ_LEVEL);
+ /* Mask all irqs */
+ irq_reg_writel(gc, IRQ_MSK(32), JZ_REG_INTC_SET_MASK);
}

setup_irq(parent_irq, &intc_cascade_action);
return 0;

+out_domain_remove:
+ irq_domain_remove(domain);
out_unmap_base:
iounmap(intc->base);
out_unmap_irq:
--
2.7.4


2019-10-02 12:19:13

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 5/5 v5] irqchip: Ingenic: Add process for more than one irq at the same time.

Add process for the situation that more than one irq is coming to
a single chip at the same time. The original code will only respond
to the lowest setted bit in JZ_REG_INTC_PENDING, and then exit the
interrupt dispatch function. After exiting the interrupt dispatch
function, since the second interrupt has not yet responded, the
interrupt dispatch function is again entered to process the second
interrupt. This creates additional unnecessary overhead, and the
more interrupts that occur at the same time, the more overhead is
added. The improved method in this patch is to check whether there
are still unresponsive interrupts after processing the lowest
setted bit interrupt. If there are any, the processing will be
processed according to the bit in JZ_REG_INTC_PENDING, and the
interrupt dispatch function will be exited until all processing
is completed.

Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 06ab3ad..c1be3d5 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <[email protected]>
- * JZ4740 platform IRQ support
+ * Ingenic XBurst platform IRQ support
*/

#include <linux/errno.h>
@@ -37,18 +37,23 @@ static irqreturn_t intc_cascade(int irq, void *data)
struct ingenic_intc_data *intc = irq_get_handler_data(irq);
struct irq_domain *domain = intc->domain;
struct irq_chip_generic *gc;
- uint32_t irq_reg;
+ uint32_t pending;
unsigned i;

for (i = 0; i < intc->num_chips; i++) {
gc = irq_get_domain_generic_chip(domain, i * 32);

- irq_reg = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
- if (!irq_reg)
+ pending = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
+ if (!pending)
continue;

- irq = irq_find_mapping(domain, __fls(irq_reg) + (i * 32));
- generic_handle_irq(irq);
+ while (pending) {
+ int bit = __fls(pending);
+
+ irq = irq_find_mapping(domain, bit + (i * 32));
+ generic_handle_irq(irq);
+ pending &= ~BIT(bit);
+ }
}

return IRQ_HANDLED;
--
2.7.4


2019-10-06 00:16:40

by Paul Cercueil

[permalink] [raw]
Subject: Re: [PATCH 1/5 v5] irqchip: ingenic: Drop redundant irq_suspend / irq_resume functions

Hi Zhou,


Le mer., oct. 2, 2019 at 19:25, Zhou Yanjie <[email protected]> a
?crit :
> From: Paul Cercueil <[email protected]>
>
> The same behaviour can be obtained by using the
> IRQCHIP_MASK_ON_SUSPEND
> flag on the IRQ chip.
>
> Signed-off-by: Paul Cercueil <[email protected]>

If you sumbit a patchset that contains someone else's patches you need
to add your Signed-off-by too.

> ---
> drivers/irqchip/irq-ingenic.c | 24 +-----------------------
> include/linux/irqchip/ingenic.h | 14 --------------
> 2 files changed, 1 insertion(+), 37 deletions(-)
> delete mode 100644 include/linux/irqchip/ingenic.h
>
> diff --git a/drivers/irqchip/irq-ingenic.c
> b/drivers/irqchip/irq-ingenic.c
> index f126255..06fa810 100644
> --- a/drivers/irqchip/irq-ingenic.c
> +++ b/drivers/irqchip/irq-ingenic.c
> @@ -10,7 +10,6 @@
> #include <linux/interrupt.h>
> #include <linux/ioport.h>
> #include <linux/irqchip.h>
> -#include <linux/irqchip/ingenic.h>
> #include <linux/of_address.h>
> #include <linux/of_irq.h>
> #include <linux/timex.h>
> @@ -50,26 +49,6 @@ static irqreturn_t intc_cascade(int irq, void
> *data)
> return IRQ_HANDLED;
> }
>
> -static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t
> mask)
> -{
> - struct irq_chip_regs *regs = &gc->chip_types->regs;
> -
> - writel(mask, gc->reg_base + regs->enable);
> - writel(~mask, gc->reg_base + regs->disable);
> -}
> -
> -void ingenic_intc_irq_suspend(struct irq_data *data)
> -{
> - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
> - intc_irq_set_mask(gc, gc->wake_active);
> -}
> -
> -void ingenic_intc_irq_resume(struct irq_data *data)
> -{
> - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
> - intc_irq_set_mask(gc, gc->mask_cache);
> -}
> -
> static struct irqaction intc_cascade_action = {
> .handler = intc_cascade,
> .name = "SoC intc cascade interrupt",
> @@ -127,8 +106,7 @@ static int __init ingenic_intc_of_init(struct
> device_node *node,
> ct->chip.irq_mask = irq_gc_mask_disable_reg;
> ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
> ct->chip.irq_set_wake = irq_gc_set_wake;
> - ct->chip.irq_suspend = ingenic_intc_irq_suspend;
> - ct->chip.irq_resume = ingenic_intc_irq_resume;
> + ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND;
>
> irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0,
> IRQ_NOPROBE | IRQ_LEVEL);
> diff --git a/include/linux/irqchip/ingenic.h
> b/include/linux/irqchip/ingenic.h
> deleted file mode 100644
> index 1465588..0000000
> --- a/include/linux/irqchip/ingenic.h
> +++ /dev/null
> @@ -1,14 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-or-later */
> -/*
> - * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
> - */
> -
> -#ifndef __LINUX_IRQCHIP_INGENIC_H__
> -#define __LINUX_IRQCHIP_INGENIC_H__
> -
> -#include <linux/irq.h>
> -
> -extern void ingenic_intc_irq_suspend(struct irq_data *data);
> -extern void ingenic_intc_irq_resume(struct irq_data *data);
> -
> -#endif
> --
> 2.7.4
>
>


2019-10-06 00:19:20

by Paul Cercueil

[permalink] [raw]
Subject: Re: [PATCH 5/5 v5] irqchip: Ingenic: Add process for more than one irq at the same time.



Le mer., oct. 2, 2019 at 19:25, Zhou Yanjie <[email protected]> a
?crit :
> Add process for the situation that more than one irq is coming to
> a single chip at the same time. The original code will only respond
> to the lowest setted bit in JZ_REG_INTC_PENDING, and then exit the
> interrupt dispatch function. After exiting the interrupt dispatch
> function, since the second interrupt has not yet responded, the
> interrupt dispatch function is again entered to process the second
> interrupt. This creates additional unnecessary overhead, and the
> more interrupts that occur at the same time, the more overhead is
> added. The improved method in this patch is to check whether there
> are still unresponsive interrupts after processing the lowest
> setted bit interrupt. If there are any, the processing will be
> processed according to the bit in JZ_REG_INTC_PENDING, and the
> interrupt dispatch function will be exited until all processing
> is completed.
>
> Signed-off-by: Zhou Yanjie <[email protected]>

Looks good to me.

Reviewed-by: Paul Cercueil <[email protected]>


> ---
> drivers/irqchip/irq-ingenic.c | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/irqchip/irq-ingenic.c
> b/drivers/irqchip/irq-ingenic.c
> index 06ab3ad..c1be3d5 100644
> --- a/drivers/irqchip/irq-ingenic.c
> +++ b/drivers/irqchip/irq-ingenic.c
> @@ -1,7 +1,7 @@
> // SPDX-License-Identifier: GPL-2.0-or-later
> /*
> * Copyright (C) 2009-2010, Lars-Peter Clausen <[email protected]>
> - * JZ4740 platform IRQ support
> + * Ingenic XBurst platform IRQ support
> */
>
> #include <linux/errno.h>
> @@ -37,18 +37,23 @@ static irqreturn_t intc_cascade(int irq, void
> *data)
> struct ingenic_intc_data *intc = irq_get_handler_data(irq);
> struct irq_domain *domain = intc->domain;
> struct irq_chip_generic *gc;
> - uint32_t irq_reg;
> + uint32_t pending;
> unsigned i;
>
> for (i = 0; i < intc->num_chips; i++) {
> gc = irq_get_domain_generic_chip(domain, i * 32);
>
> - irq_reg = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
> - if (!irq_reg)
> + pending = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
> + if (!pending)
> continue;
>
> - irq = irq_find_mapping(domain, __fls(irq_reg) + (i * 32));
> - generic_handle_irq(irq);
> + while (pending) {
> + int bit = __fls(pending);
> +
> + irq = irq_find_mapping(domain, bit + (i * 32));
> + generic_handle_irq(irq);
> + pending &= ~BIT(bit);
> + }
> }
>
> return IRQ_HANDLED;
> --
> 2.7.4
>
>


2019-10-06 06:05:19

by Zhou Yanjie

[permalink] [raw]
Subject: Re: [PATCH 1/5 v5] irqchip: ingenic: Drop redundant irq_suspend / irq_resume functions

Hi Pual,

On 2019年10月06日 08:13, Paul Cercueil wrote:
> Hi Zhou,
>
>
> Le mer., oct. 2, 2019 at 19:25, Zhou Yanjie <[email protected]> a
> écrit :
>> From: Paul Cercueil <[email protected]>
>>
>> The same behaviour can be obtained by using the IRQCHIP_MASK_ON_SUSPEND
>> flag on the IRQ chip.
>>
>> Signed-off-by: Paul Cercueil <[email protected]>
>
> If you sumbit a patchset that contains someone else's patches you need
> to add your Signed-off-by too.

Thank you for the reminder. I'll add my Signed-off-by in v6.
>
>> ---
>> drivers/irqchip/irq-ingenic.c | 24 +-----------------------
>> include/linux/irqchip/ingenic.h | 14 --------------
>> 2 files changed, 1 insertion(+), 37 deletions(-)
>> delete mode 100644 include/linux/irqchip/ingenic.h
>>
>> diff --git a/drivers/irqchip/irq-ingenic.c
>> b/drivers/irqchip/irq-ingenic.c
>> index f126255..06fa810 100644
>> --- a/drivers/irqchip/irq-ingenic.c
>> +++ b/drivers/irqchip/irq-ingenic.c
>> @@ -10,7 +10,6 @@
>> #include <linux/interrupt.h>
>> #include <linux/ioport.h>
>> #include <linux/irqchip.h>
>> -#include <linux/irqchip/ingenic.h>
>> #include <linux/of_address.h>
>> #include <linux/of_irq.h>
>> #include <linux/timex.h>
>> @@ -50,26 +49,6 @@ static irqreturn_t intc_cascade(int irq, void *data)
>> return IRQ_HANDLED;
>> }
>>
>> -static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t
>> mask)
>> -{
>> - struct irq_chip_regs *regs = &gc->chip_types->regs;
>> -
>> - writel(mask, gc->reg_base + regs->enable);
>> - writel(~mask, gc->reg_base + regs->disable);
>> -}
>> -
>> -void ingenic_intc_irq_suspend(struct irq_data *data)
>> -{
>> - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
>> - intc_irq_set_mask(gc, gc->wake_active);
>> -}
>> -
>> -void ingenic_intc_irq_resume(struct irq_data *data)
>> -{
>> - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
>> - intc_irq_set_mask(gc, gc->mask_cache);
>> -}
>> -
>> static struct irqaction intc_cascade_action = {
>> .handler = intc_cascade,
>> .name = "SoC intc cascade interrupt",
>> @@ -127,8 +106,7 @@ static int __init ingenic_intc_of_init(struct
>> device_node *node,
>> ct->chip.irq_mask = irq_gc_mask_disable_reg;
>> ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
>> ct->chip.irq_set_wake = irq_gc_set_wake;
>> - ct->chip.irq_suspend = ingenic_intc_irq_suspend;
>> - ct->chip.irq_resume = ingenic_intc_irq_resume;
>> + ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND;
>>
>> irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0,
>> IRQ_NOPROBE | IRQ_LEVEL);
>> diff --git a/include/linux/irqchip/ingenic.h
>> b/include/linux/irqchip/ingenic.h
>> deleted file mode 100644
>> index 1465588..0000000
>> --- a/include/linux/irqchip/ingenic.h
>> +++ /dev/null
>> @@ -1,14 +0,0 @@
>> -/* SPDX-License-Identifier: GPL-2.0-or-later */
>> -/*
>> - * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
>> - */
>> -
>> -#ifndef __LINUX_IRQCHIP_INGENIC_H__
>> -#define __LINUX_IRQCHIP_INGENIC_H__
>> -
>> -#include <linux/irq.h>
>> -
>> -extern void ingenic_intc_irq_suspend(struct irq_data *data);
>> -extern void ingenic_intc_irq_resume(struct irq_data *data);
>> -
>> -#endif
>> --
>> 2.7.4
>>
>>
>
>



2019-10-12 05:57:59

by Zhou Yanjie

[permalink] [raw]
Subject: Add process for more than one irq at the same time v6

v5->v6: add my Signed-off-by for patches from Paul Cercueil.


2019-10-12 05:59:59

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 4/5 v6] irqchip: ingenic: Alloc generic chips from IRQ domain

From: Paul Cercueil <[email protected]>

By creating the generic chips from the IRQ domain, we don't rely on the
JZ4740_IRQ_BASE macro. It also makes the code a bit cleaner.

Signed-off-by: Paul Cercueil <[email protected]>
Signed-off-by: Zhou Yanjie <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 82a079f..06ab3ad 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -36,12 +36,14 @@ static irqreturn_t intc_cascade(int irq, void *data)
{
struct ingenic_intc_data *intc = irq_get_handler_data(irq);
struct irq_domain *domain = intc->domain;
+ struct irq_chip_generic *gc;
uint32_t irq_reg;
unsigned i;

for (i = 0; i < intc->num_chips; i++) {
- irq_reg = readl(intc->base + (i * CHIP_SIZE) +
- JZ_REG_INTC_PENDING);
+ gc = irq_get_domain_generic_chip(domain, i * 32);
+
+ irq_reg = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
if (!irq_reg)
continue;

@@ -92,7 +94,7 @@ static int __init ingenic_intc_of_init(struct device_node *node,

domain = irq_domain_add_legacy(node, num_chips * 32,
JZ4740_IRQ_BASE, 0,
- &irq_domain_simple_ops, NULL);
+ &irq_generic_chip_ops, NULL);
if (!domain) {
err = -ENOMEM;
goto out_unmap_base;
@@ -100,17 +102,17 @@ static int __init ingenic_intc_of_init(struct device_node *node,

intc->domain = domain;

- for (i = 0; i < num_chips; i++) {
- /* Mask all irqs */
- writel(0xffffffff, intc->base + (i * CHIP_SIZE) +
- JZ_REG_INTC_SET_MASK);
+ err = irq_alloc_domain_generic_chips(domain, 32, 1, "INTC",
+ handle_level_irq, 0,
+ IRQ_NOPROBE | IRQ_LEVEL, 0);
+ if (err)
+ goto out_domain_remove;

- gc = irq_alloc_generic_chip("INTC", 1,
- JZ4740_IRQ_BASE + (i * 32),
- intc->base + (i * CHIP_SIZE),
- handle_level_irq);
+ for (i = 0; i < num_chips; i++) {
+ gc = irq_get_domain_generic_chip(domain, i * 32);

gc->wake_enabled = IRQ_MSK(32);
+ gc->reg_base = intc->base + (i * CHIP_SIZE);

ct = gc->chip_types;
ct->regs.enable = JZ_REG_INTC_CLEAR_MASK;
@@ -121,13 +123,15 @@ static int __init ingenic_intc_of_init(struct device_node *node,
ct->chip.irq_set_wake = irq_gc_set_wake;
ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND;

- irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0,
- IRQ_NOPROBE | IRQ_LEVEL);
+ /* Mask all irqs */
+ irq_reg_writel(gc, IRQ_MSK(32), JZ_REG_INTC_SET_MASK);
}

setup_irq(parent_irq, &intc_cascade_action);
return 0;

+out_domain_remove:
+ irq_domain_remove(domain);
out_unmap_base:
iounmap(intc->base);
out_unmap_irq:
--
2.7.4


2019-10-12 06:00:19

by Zhou Yanjie

[permalink] [raw]
Subject: [PATCH 5/5 v6] irqchip: Ingenic: Add process for more than one irq at the same time.

Add process for the situation that more than one irq is coming to
a single chip at the same time. The original code will only respond
to the lowest setted bit in JZ_REG_INTC_PENDING, and then exit the
interrupt dispatch function. After exiting the interrupt dispatch
function, since the second interrupt has not yet responded, the
interrupt dispatch function is again entered to process the second
interrupt. This creates additional unnecessary overhead, and the
more interrupts that occur at the same time, the more overhead is
added. The improved method in this patch is to check whether there
are still unresponsive interrupts after processing the lowest
setted bit interrupt. If there are any, the processing will be
processed according to the bit in JZ_REG_INTC_PENDING, and the
interrupt dispatch function will be exited until all processing
is completed.

Signed-off-by: Zhou Yanjie <[email protected]>
Reviewed-by: Paul Cercueil <[email protected]>
---
drivers/irqchip/irq-ingenic.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 06ab3ad..01d18b3 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <[email protected]>
- * JZ4740 platform IRQ support
+ * Ingenic XBurst platform IRQ support
*/

#include <linux/errno.h>
@@ -37,18 +37,23 @@ static irqreturn_t intc_cascade(int irq, void *data)
struct ingenic_intc_data *intc = irq_get_handler_data(irq);
struct irq_domain *domain = intc->domain;
struct irq_chip_generic *gc;
- uint32_t irq_reg;
+ uint32_t pending;
unsigned i;

for (i = 0; i < intc->num_chips; i++) {
gc = irq_get_domain_generic_chip(domain, i * 32);

- irq_reg = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
- if (!irq_reg)
+ pending = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
+ if (!pending)
continue;

- irq = irq_find_mapping(domain, __fls(irq_reg) + (i * 32));
- generic_handle_irq(irq);
+ while (pending) {
+ int bit = __fls(pending);
+
+ irq = irq_find_mapping(domain, bit + (i * 32));
+ generic_handle_irq(irq);
+ pending &= ~BIT(bit);
+ }
}

return IRQ_HANDLED;
--
2.7.4


Subject: [tip: irq/core] irqchip: ingenic: Get virq number from IRQ domain

The following commit has been merged into the irq/core branch of tip:

Commit-ID: 208caadce5d4d38f48af965206bbd4473d265080
Gitweb: https://git.kernel.org/tip/208caadce5d4d38f48af965206bbd4473d265080
Author: Paul Cercueil <[email protected]>
AuthorDate: Wed, 02 Oct 2019 19:25:23 +08:00
Committer: Marc Zyngier <[email protected]>
CommitterDate: Sun, 10 Nov 2019 18:55:30

irqchip: ingenic: Get virq number from IRQ domain

Get the virq number from the IRQ domain instead of calculating it from
the hardcoded irq base.

Signed-off-by: Paul Cercueil <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
drivers/irqchip/irq-ingenic.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index d97a3a5..82a079f 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -21,6 +21,7 @@

struct ingenic_intc_data {
void __iomem *base;
+ struct irq_domain *domain;
unsigned num_chips;
};

@@ -34,6 +35,7 @@ struct ingenic_intc_data {
static irqreturn_t intc_cascade(int irq, void *data)
{
struct ingenic_intc_data *intc = irq_get_handler_data(irq);
+ struct irq_domain *domain = intc->domain;
uint32_t irq_reg;
unsigned i;

@@ -43,7 +45,8 @@ static irqreturn_t intc_cascade(int irq, void *data)
if (!irq_reg)
continue;

- generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE);
+ irq = irq_find_mapping(domain, __fls(irq_reg) + (i * 32));
+ generic_handle_irq(irq);
}

return IRQ_HANDLED;
@@ -95,6 +98,8 @@ static int __init ingenic_intc_of_init(struct device_node *node,
goto out_unmap_base;
}

+ intc->domain = domain;
+
for (i = 0; i < num_chips; i++) {
/* Mask all irqs */
writel(0xffffffff, intc->base + (i * CHIP_SIZE) +

Subject: [tip: irq/core] irqchip: Ingenic: Add process for more than one irq at the same time.

The following commit has been merged into the irq/core branch of tip:

Commit-ID: b8b0145f7d0e24d98a58b7e54051dca0c1d77526
Gitweb: https://git.kernel.org/tip/b8b0145f7d0e24d98a58b7e54051dca0c1d77526
Author: Zhou Yanjie <[email protected]>
AuthorDate: Wed, 02 Oct 2019 19:25:25 +08:00
Committer: Marc Zyngier <[email protected]>
CommitterDate: Sun, 10 Nov 2019 18:55:31

irqchip: Ingenic: Add process for more than one irq at the same time.

Add process for the situation that more than one irq is coming to
a single chip at the same time. The original code will only respond
to the lowest setted bit in JZ_REG_INTC_PENDING, and then exit the
interrupt dispatch function. After exiting the interrupt dispatch
function, since the second interrupt has not yet responded, the
interrupt dispatch function is again entered to process the second
interrupt. This creates additional unnecessary overhead, and the
more interrupts that occur at the same time, the more overhead is
added. The improved method in this patch is to check whether there
are still unresponsive interrupts after processing the lowest
setted bit interrupt. If there are any, the processing will be
processed according to the bit in JZ_REG_INTC_PENDING, and the
interrupt dispatch function will be exited until all processing
is completed.

Signed-off-by: Zhou Yanjie <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
Reviewed-by: Paul Cercueil <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
drivers/irqchip/irq-ingenic.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 06ab3ad..01d18b3 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <[email protected]>
- * JZ4740 platform IRQ support
+ * Ingenic XBurst platform IRQ support
*/

#include <linux/errno.h>
@@ -37,18 +37,23 @@ static irqreturn_t intc_cascade(int irq, void *data)
struct ingenic_intc_data *intc = irq_get_handler_data(irq);
struct irq_domain *domain = intc->domain;
struct irq_chip_generic *gc;
- uint32_t irq_reg;
+ uint32_t pending;
unsigned i;

for (i = 0; i < intc->num_chips; i++) {
gc = irq_get_domain_generic_chip(domain, i * 32);

- irq_reg = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
- if (!irq_reg)
+ pending = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
+ if (!pending)
continue;

- irq = irq_find_mapping(domain, __fls(irq_reg) + (i * 32));
- generic_handle_irq(irq);
+ while (pending) {
+ int bit = __fls(pending);
+
+ irq = irq_find_mapping(domain, bit + (i * 32));
+ generic_handle_irq(irq);
+ pending &= ~BIT(bit);
+ }
}

return IRQ_HANDLED;

Subject: [tip: irq/core] irqchip: ingenic: Error out if IRQ domain creation failed

The following commit has been merged into the irq/core branch of tip:

Commit-ID: 52ecc87642f273a599c9913b29fd179c13de457b
Gitweb: https://git.kernel.org/tip/52ecc87642f273a599c9913b29fd179c13de457b
Author: Paul Cercueil <[email protected]>
AuthorDate: Wed, 02 Oct 2019 19:25:22 +08:00
Committer: Marc Zyngier <[email protected]>
CommitterDate: Sun, 10 Nov 2019 18:55:30

irqchip: ingenic: Error out if IRQ domain creation failed

If we cannot create the IRQ domain, the driver should fail to probe
instead of succeeding with just a warning message.

Signed-off-by: Paul Cercueil <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
drivers/irqchip/irq-ingenic.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 06fa810..d97a3a5 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -87,6 +87,14 @@ static int __init ingenic_intc_of_init(struct device_node *node,
goto out_unmap_irq;
}

+ domain = irq_domain_add_legacy(node, num_chips * 32,
+ JZ4740_IRQ_BASE, 0,
+ &irq_domain_simple_ops, NULL);
+ if (!domain) {
+ err = -ENOMEM;
+ goto out_unmap_base;
+ }
+
for (i = 0; i < num_chips; i++) {
/* Mask all irqs */
writel(0xffffffff, intc->base + (i * CHIP_SIZE) +
@@ -112,14 +120,11 @@ static int __init ingenic_intc_of_init(struct device_node *node,
IRQ_NOPROBE | IRQ_LEVEL);
}

- domain = irq_domain_add_legacy(node, num_chips * 32, JZ4740_IRQ_BASE, 0,
- &irq_domain_simple_ops, NULL);
- if (!domain)
- pr_warn("unable to register IRQ domain\n");
-
setup_irq(parent_irq, &intc_cascade_action);
return 0;

+out_unmap_base:
+ iounmap(intc->base);
out_unmap_irq:
irq_dispose_mapping(parent_irq);
out_free:

Subject: [tip: irq/core] irqchip: ingenic: Drop redundant irq_suspend / irq_resume functions

The following commit has been merged into the irq/core branch of tip:

Commit-ID: 20b44b4de61f2887694981e8cae74fe1bf58f950
Gitweb: https://git.kernel.org/tip/20b44b4de61f2887694981e8cae74fe1bf58f950
Author: Paul Cercueil <[email protected]>
AuthorDate: Wed, 02 Oct 2019 19:25:21 +08:00
Committer: Marc Zyngier <[email protected]>
CommitterDate: Sun, 10 Nov 2019 18:55:29

irqchip: ingenic: Drop redundant irq_suspend / irq_resume functions

The same behaviour can be obtained by using the IRQCHIP_MASK_ON_SUSPEND
flag on the IRQ chip.

Signed-off-by: Paul Cercueil <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
drivers/irqchip/irq-ingenic.c | 24 +-----------------------
include/linux/irqchip/ingenic.h | 14 --------------
2 files changed, 1 insertion(+), 37 deletions(-)
delete mode 100644 include/linux/irqchip/ingenic.h

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index f126255..06fa810 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -10,7 +10,6 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/irqchip.h>
-#include <linux/irqchip/ingenic.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/timex.h>
@@ -50,26 +49,6 @@ static irqreturn_t intc_cascade(int irq, void *data)
return IRQ_HANDLED;
}

-static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask)
-{
- struct irq_chip_regs *regs = &gc->chip_types->regs;
-
- writel(mask, gc->reg_base + regs->enable);
- writel(~mask, gc->reg_base + regs->disable);
-}
-
-void ingenic_intc_irq_suspend(struct irq_data *data)
-{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- intc_irq_set_mask(gc, gc->wake_active);
-}
-
-void ingenic_intc_irq_resume(struct irq_data *data)
-{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- intc_irq_set_mask(gc, gc->mask_cache);
-}
-
static struct irqaction intc_cascade_action = {
.handler = intc_cascade,
.name = "SoC intc cascade interrupt",
@@ -127,8 +106,7 @@ static int __init ingenic_intc_of_init(struct device_node *node,
ct->chip.irq_mask = irq_gc_mask_disable_reg;
ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
ct->chip.irq_set_wake = irq_gc_set_wake;
- ct->chip.irq_suspend = ingenic_intc_irq_suspend;
- ct->chip.irq_resume = ingenic_intc_irq_resume;
+ ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND;

irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0,
IRQ_NOPROBE | IRQ_LEVEL);
diff --git a/include/linux/irqchip/ingenic.h b/include/linux/irqchip/ingenic.h
deleted file mode 100644
index 1465588..0000000
--- a/include/linux/irqchip/ingenic.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
- */
-
-#ifndef __LINUX_IRQCHIP_INGENIC_H__
-#define __LINUX_IRQCHIP_INGENIC_H__
-
-#include <linux/irq.h>
-
-extern void ingenic_intc_irq_suspend(struct irq_data *data);
-extern void ingenic_intc_irq_resume(struct irq_data *data);
-
-#endif

Subject: [tip: irq/core] irqchip: ingenic: Alloc generic chips from IRQ domain

The following commit has been merged into the irq/core branch of tip:

Commit-ID: 8bc7464b5140218cb714abae55ea4cfe26b30c96
Gitweb: https://git.kernel.org/tip/8bc7464b5140218cb714abae55ea4cfe26b30c96
Author: Paul Cercueil <[email protected]>
AuthorDate: Wed, 02 Oct 2019 19:25:24 +08:00
Committer: Marc Zyngier <[email protected]>
CommitterDate: Sun, 10 Nov 2019 18:55:30

irqchip: ingenic: Alloc generic chips from IRQ domain

By creating the generic chips from the IRQ domain, we don't rely on the
JZ4740_IRQ_BASE macro. It also makes the code a bit cleaner.

Signed-off-by: Paul Cercueil <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
drivers/irqchip/irq-ingenic.c | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 82a079f..06ab3ad 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -36,12 +36,14 @@ static irqreturn_t intc_cascade(int irq, void *data)
{
struct ingenic_intc_data *intc = irq_get_handler_data(irq);
struct irq_domain *domain = intc->domain;
+ struct irq_chip_generic *gc;
uint32_t irq_reg;
unsigned i;

for (i = 0; i < intc->num_chips; i++) {
- irq_reg = readl(intc->base + (i * CHIP_SIZE) +
- JZ_REG_INTC_PENDING);
+ gc = irq_get_domain_generic_chip(domain, i * 32);
+
+ irq_reg = irq_reg_readl(gc, JZ_REG_INTC_PENDING);
if (!irq_reg)
continue;

@@ -92,7 +94,7 @@ static int __init ingenic_intc_of_init(struct device_node *node,

domain = irq_domain_add_legacy(node, num_chips * 32,
JZ4740_IRQ_BASE, 0,
- &irq_domain_simple_ops, NULL);
+ &irq_generic_chip_ops, NULL);
if (!domain) {
err = -ENOMEM;
goto out_unmap_base;
@@ -100,17 +102,17 @@ static int __init ingenic_intc_of_init(struct device_node *node,

intc->domain = domain;

- for (i = 0; i < num_chips; i++) {
- /* Mask all irqs */
- writel(0xffffffff, intc->base + (i * CHIP_SIZE) +
- JZ_REG_INTC_SET_MASK);
+ err = irq_alloc_domain_generic_chips(domain, 32, 1, "INTC",
+ handle_level_irq, 0,
+ IRQ_NOPROBE | IRQ_LEVEL, 0);
+ if (err)
+ goto out_domain_remove;

- gc = irq_alloc_generic_chip("INTC", 1,
- JZ4740_IRQ_BASE + (i * 32),
- intc->base + (i * CHIP_SIZE),
- handle_level_irq);
+ for (i = 0; i < num_chips; i++) {
+ gc = irq_get_domain_generic_chip(domain, i * 32);

gc->wake_enabled = IRQ_MSK(32);
+ gc->reg_base = intc->base + (i * CHIP_SIZE);

ct = gc->chip_types;
ct->regs.enable = JZ_REG_INTC_CLEAR_MASK;
@@ -121,13 +123,15 @@ static int __init ingenic_intc_of_init(struct device_node *node,
ct->chip.irq_set_wake = irq_gc_set_wake;
ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND;

- irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0,
- IRQ_NOPROBE | IRQ_LEVEL);
+ /* Mask all irqs */
+ irq_reg_writel(gc, IRQ_MSK(32), JZ_REG_INTC_SET_MASK);
}

setup_irq(parent_irq, &intc_cascade_action);
return 0;

+out_domain_remove:
+ irq_domain_remove(domain);
out_unmap_base:
iounmap(intc->base);
out_unmap_irq: