Re: [PATCH V2 4/4] irq: imx: irqsteer: add multi output interrupts support

2019-01-30 Thread Lucas Stach
Am Mittwoch, den 30.01.2019, 22:03 +0800 schrieb Dong Aisheng:
> > On Wed, Jan 30, 2019 at 9:33 PM Lucas Stach  wrote:
> > 
> > Am Mittwoch, den 30.01.2019, 13:06 + schrieb Aisheng Dong:
> > > One irqsteer channel can support up to 8 output interrupts.
> > > 
> > > > > > > > Cc: Marc Zyngier 
> > > > > > > > Cc: Lucas Stach 
> > > > > > > > Cc: Shawn Guo 
> > > > Signed-off-by: Dong Aisheng 
> > > 
> > > ---
> > > ChangeLog:
> > > v1->v2:
> > >  * calculate irq_count by fsl,num-irqs instead of parsing interrupts
> > >    property from devicetree to match the input interrupts and outputs
> > >  * improve output interrupt handler by searching only two registers
> > >    withint the same group
> > > ---
> > >  drivers/irqchip/irq-imx-irqsteer.c | 76 
> > > +-
> > >  1 file changed, 59 insertions(+), 17 deletions(-)
> > > 
> > > diff --git a/drivers/irqchip/irq-imx-irqsteer.c 
> > > b/drivers/irqchip/irq-imx-irqsteer.c
> > > index 67ed862..cc40039 100644
> > > --- a/drivers/irqchip/irq-imx-irqsteer.c
> > > +++ b/drivers/irqchip/irq-imx-irqsteer.c
> > > @@ -10,6 +10,7 @@
> > >  #include 
> > >  #include 
> > >  #include 
> > > +#include 
> > >  #include 
> > >  #include 
> > > 
> > > @@ -21,10 +22,13 @@
> > > >  #define CHAN_MINTDIS(t)(CTRL_STRIDE_OFF(t, 3) + 0x4)
> > > >  #define CHAN_MASTRSTAT(t)  (CTRL_STRIDE_OFF(t, 3) + 0x8)
> > > > +#define CHAN_MAX_OUTPUT_INT0x8
> > > 
> > > +
> > >  struct irqsteer_data {
> > > > >   void __iomem*regs;
> > > > >   struct clk  *ipg_clk;
> > > > > - int irq;
> > > > > + int irq[CHAN_MAX_OUTPUT_INT];
> > > > > + int irq_count;
> > > > >   raw_spinlock_t  lock;
> > > > >   int reg_num;
> > > > >   int channel;
> > > 
> > > @@ -87,26 +91,45 @@ static const struct irq_domain_ops 
> > > imx_irqsteer_domain_ops = {
> > > > >   .xlate  = irq_domain_xlate_onecell,
> > > 
> > >  };
> > > 
> > > +static int imx_irqsteer_get_hwirq_base(struct irqsteer_data *data, u32 
> > > irq)
> > > +{
> > > > +   int i;
> > > 
> > > +
> > > > +   for (i = 0; i < data->irq_count; i++) {
> > > > +   if (data->irq[i] == irq)
> > > 
> > > + break;
> > 
> > return i * 64; here...
> > > + }
> > > +
> > > + return i * 64;
> > 
> > ... and -EINVAL or something here, so we don't return a out of bounds
> > hwirq base if the loop ever doesn't match something?
> > 
> 
> Good suggestion, will add it.
> 
> > > +}
> > > +
> > >  static void imx_irqsteer_irq_handler(struct irq_desc *desc)
> > >  {
> > > > struct irqsteer_data *data = irq_desc_get_handler_data(desc);
> > > > +   int hwirq;
> > > > int i;
> > > > chained_irq_enter(irq_desc_get_chip(desc), desc);
> > > > -   for (i = 0; i < data->reg_num * 32; i += 32) {
> > > > -   int idx = imx_irqsteer_get_reg_index(data, i);
> > > > +   hwirq = imx_irqsteer_get_hwirq_base(data, irq_desc_get_irq(desc));
> > > 
> > > +
> > > > +   for (i = 0; i < 2; i++) {
> > > > +   int idx = imx_irqsteer_get_reg_index(data, hwirq);
> > > > unsigned long irqmap;
> > > > int pos, virq;
> > > > +   if (hwirq >= data->reg_num * 32)
> > > > +   break;
> > > 
> > > +
> > > > irqmap = readl_relaxed(data->regs +
> > > >    CHANSTATUS(idx, data->reg_num));
> > > > for_each_set_bit(pos, , 32) {
> > > > -   virq = irq_find_mapping(data->domain, pos + i);
> > > 
> > > + virq = irq_find_mapping(data->domain, pos + hwirq);
> > 
> > The irq index calculation need to be "pos + i * 32 + hwirq", otherwise
> > this will map to the wrong virqs for the second register in each group.
> > 
> 
> For second register map, hwirq will plus 32 in next round.
> So i can't see this will map a wrong virqs.
> And it looks to me ""pos + i * 32 + hwirq" is equal to "hwirq + 32".
> Am i missed something?

You are right, I forgot about the hwirq being incremented in the loop
when writing this comment.

> > >   if (virq)
> > > > generic_handle_irq(virq);
> > > > }
> > > 
> > > + hwirq += 32;
> > 
> > Could be folded into the loop head.
> > 
> 
> You mean “for (i = 0; i < 2; i++, hwirq +=32)” ?
> I feel that's not quite necessary.

I personally find that quite a bit clearer than incrementing the loop
variables at different spots. And I probably wouldn't have missed hwirq
being incremented in the loop if I had seen it in the head.

Regards,
Lucas


Re: [PATCH V2 4/4] irq: imx: irqsteer: add multi output interrupts support

2019-01-30 Thread Dong Aisheng
On Wed, Jan 30, 2019 at 9:33 PM Lucas Stach  wrote:
>
> Am Mittwoch, den 30.01.2019, 13:06 + schrieb Aisheng Dong:
> > One irqsteer channel can support up to 8 output interrupts.
> >
> > > Cc: Marc Zyngier 
> > > Cc: Lucas Stach 
> > > Cc: Shawn Guo 
> > > Signed-off-by: Dong Aisheng 
> > ---
> > ChangeLog:
> > v1->v2:
> >  * calculate irq_count by fsl,num-irqs instead of parsing interrupts
> >property from devicetree to match the input interrupts and outputs
> >  * improve output interrupt handler by searching only two registers
> >withint the same group
> > ---
> >  drivers/irqchip/irq-imx-irqsteer.c | 76 
> > +-
> >  1 file changed, 59 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/irqchip/irq-imx-irqsteer.c 
> > b/drivers/irqchip/irq-imx-irqsteer.c
> > index 67ed862..cc40039 100644
> > --- a/drivers/irqchip/irq-imx-irqsteer.c
> > +++ b/drivers/irqchip/irq-imx-irqsteer.c
> > @@ -10,6 +10,7 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >  #include 
> >  #include 
> >
> > @@ -21,10 +22,13 @@
> > >  #define CHAN_MINTDIS(t)(CTRL_STRIDE_OFF(t, 3) + 0x4)
> > >  #define CHAN_MASTRSTAT(t)  (CTRL_STRIDE_OFF(t, 3) + 0x8)
> >
> > > +#define CHAN_MAX_OUTPUT_INT0x8
> > +
> >  struct irqsteer_data {
> > > >   void __iomem*regs;
> > > >   struct clk  *ipg_clk;
> > > > - int irq;
> > > > + int irq[CHAN_MAX_OUTPUT_INT];
> > > > + int irq_count;
> > > >   raw_spinlock_t  lock;
> > > >   int reg_num;
> > > >   int channel;
> > @@ -87,26 +91,45 @@ static const struct irq_domain_ops 
> > imx_irqsteer_domain_ops = {
> > > >   .xlate  = irq_domain_xlate_onecell,
> >  };
> >
> > +static int imx_irqsteer_get_hwirq_base(struct irqsteer_data *data, u32 irq)
> > +{
> > > +   int i;
> > +
> > > +   for (i = 0; i < data->irq_count; i++) {
> > > +   if (data->irq[i] == irq)
> > + break;
>
> return i * 64; here...
> > + }
> > +
> > + return i * 64;
>
> ... and -EINVAL or something here, so we don't return a out of bounds
> hwirq base if the loop ever doesn't match something?
>

Good suggestion, will add it.

> > +}
> > +
> >  static void imx_irqsteer_irq_handler(struct irq_desc *desc)
> >  {
> > > struct irqsteer_data *data = irq_desc_get_handler_data(desc);
> > > +   int hwirq;
> > > int i;
> >
> > > chained_irq_enter(irq_desc_get_chip(desc), desc);
> >
> > > -   for (i = 0; i < data->reg_num * 32; i += 32) {
> > > -   int idx = imx_irqsteer_get_reg_index(data, i);
> > > +   hwirq = imx_irqsteer_get_hwirq_base(data, irq_desc_get_irq(desc));
> > +
> > > +   for (i = 0; i < 2; i++) {
> > > +   int idx = imx_irqsteer_get_reg_index(data, hwirq);
> > > unsigned long irqmap;
> > > int pos, virq;
> >
> > > +   if (hwirq >= data->reg_num * 32)
> > > +   break;
> > +
> > > irqmap = readl_relaxed(data->regs +
> > >CHANSTATUS(idx, data->reg_num));
> >
> > > for_each_set_bit(pos, , 32) {
> > > -   virq = irq_find_mapping(data->domain, pos + i);
> > + virq = irq_find_mapping(data->domain, pos + hwirq);
>
> The irq index calculation need to be "pos + i * 32 + hwirq", otherwise
> this will map to the wrong virqs for the second register in each group.
>

For second register map, hwirq will plus 32 in next round.
So i can't see this will map a wrong virqs.
And it looks to me ""pos + i * 32 + hwirq" is equal to "hwirq + 32".
Am i missed something?

> >   if (virq)
> > > generic_handle_irq(virq);
> > > }
> > + hwirq += 32;
>
> Could be folded into the loop head.
>

You mean “for (i = 0; i < 2; i++, hwirq +=32)” ?
I feel that's not quite necessary.

> >   }
> >
> > > chained_irq_exit(irq_desc_get_chip(desc), desc);
> > @@ -117,7 +140,8 @@ static int imx_irqsteer_probe(struct platform_device 
> > *pdev)
> > > struct device_node *np = pdev->dev.of_node;
> > > struct irqsteer_data *data;
> > > struct resource *res;
> > > -   int ret;
> > > +   u32 irqs_num;
> > > +   int i, ret;
> >
> > > data = devm_kzalloc(>dev, sizeof(*data), GFP_KERNEL);
> > > if (!data)
> > @@ -130,12 +154,6 @@ static int imx_irqsteer_probe(struct platform_device 
> > *pdev)
> > > return PTR_ERR(data->regs);
> > > }
> >
> > > -   data->irq = platform_get_irq(pdev, 0);
> > > -   if (data->irq <= 0) {
> > > -   dev_err(>dev, "failed to get irq\n");
> > > -   return -ENODEV;
> > > -   }
> > -
> > > data->ipg_clk = devm_clk_get(>dev, "ipg");
> > > if (IS_ERR(data->ipg_clk)) {
> > > ret = PTR_ERR(data->ipg_clk);
> > @@ -146,11 +164,17 @@ static int imx_irqsteer_probe(struct platform_device 
> > 

Re: [PATCH V2 4/4] irq: imx: irqsteer: add multi output interrupts support

2019-01-30 Thread Lucas Stach
Am Mittwoch, den 30.01.2019, 13:06 + schrieb Aisheng Dong:
> One irqsteer channel can support up to 8 output interrupts.
> 
> > Cc: Marc Zyngier 
> > Cc: Lucas Stach 
> > Cc: Shawn Guo 
> > Signed-off-by: Dong Aisheng 
> ---
> ChangeLog:
> v1->v2:
>  * calculate irq_count by fsl,num-irqs instead of parsing interrupts
>    property from devicetree to match the input interrupts and outputs
>  * improve output interrupt handler by searching only two registers
>    withint the same group
> ---
>  drivers/irqchip/irq-imx-irqsteer.c | 76 
> +-
>  1 file changed, 59 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-imx-irqsteer.c 
> b/drivers/irqchip/irq-imx-irqsteer.c
> index 67ed862..cc40039 100644
> --- a/drivers/irqchip/irq-imx-irqsteer.c
> +++ b/drivers/irqchip/irq-imx-irqsteer.c
> @@ -10,6 +10,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  
> @@ -21,10 +22,13 @@
> >  #define CHAN_MINTDIS(t)(CTRL_STRIDE_OFF(t, 3) + 0x4)
> >  #define CHAN_MASTRSTAT(t)  (CTRL_STRIDE_OFF(t, 3) + 0x8)
>  
> > +#define CHAN_MAX_OUTPUT_INT0x8
> +
>  struct irqsteer_data {
> > >   void __iomem*regs;
> > >   struct clk  *ipg_clk;
> > > - int irq;
> > > + int irq[CHAN_MAX_OUTPUT_INT];
> > > + int irq_count;
> > >   raw_spinlock_t  lock;
> > >   int reg_num;
> > >   int channel;
> @@ -87,26 +91,45 @@ static const struct irq_domain_ops 
> imx_irqsteer_domain_ops = {
> > >   .xlate  = irq_domain_xlate_onecell,
>  };
>  
> +static int imx_irqsteer_get_hwirq_base(struct irqsteer_data *data, u32 irq)
> +{
> > +   int i;
> +
> > +   for (i = 0; i < data->irq_count; i++) {
> > +   if (data->irq[i] == irq)
> + break;

return i * 64; here...
> + }
> +
> + return i * 64;

... and -EINVAL or something here, so we don't return a out of bounds
hwirq base if the loop ever doesn't match something?
 
> +}
> +
>  static void imx_irqsteer_irq_handler(struct irq_desc *desc)
>  {
> >     struct irqsteer_data *data = irq_desc_get_handler_data(desc);
> > +   int hwirq;
> >     int i;
>  
> >     chained_irq_enter(irq_desc_get_chip(desc), desc);
>  
> > -   for (i = 0; i < data->reg_num * 32; i += 32) {
> > -   int idx = imx_irqsteer_get_reg_index(data, i);
> > +   hwirq = imx_irqsteer_get_hwirq_base(data, irq_desc_get_irq(desc));
> +
> > +   for (i = 0; i < 2; i++) {
> > +   int idx = imx_irqsteer_get_reg_index(data, hwirq);
> >     unsigned long irqmap;
> >     int pos, virq;
>  
> > +   if (hwirq >= data->reg_num * 32)
> > +   break;
> +
> >     irqmap = readl_relaxed(data->regs +
> >        CHANSTATUS(idx, data->reg_num));
>  
> >     for_each_set_bit(pos, , 32) {
> > -   virq = irq_find_mapping(data->domain, pos + i);
> + virq = irq_find_mapping(data->domain, pos + hwirq);

The irq index calculation need to be "pos + i * 32 + hwirq", otherwise
this will map to the wrong virqs for the second register in each group.

>   if (virq)
> >     generic_handle_irq(virq);
> >     }
> + hwirq += 32;

Could be folded into the loop head.

>   }
>  
> >     chained_irq_exit(irq_desc_get_chip(desc), desc);
> @@ -117,7 +140,8 @@ static int imx_irqsteer_probe(struct platform_device 
> *pdev)
> >     struct device_node *np = pdev->dev.of_node;
> >     struct irqsteer_data *data;
> >     struct resource *res;
> > -   int ret;
> > +   u32 irqs_num;
> > +   int i, ret;
>  
> >     data = devm_kzalloc(>dev, sizeof(*data), GFP_KERNEL);
> >     if (!data)
> @@ -130,12 +154,6 @@ static int imx_irqsteer_probe(struct platform_device 
> *pdev)
> >     return PTR_ERR(data->regs);
> >     }
>  
> > -   data->irq = platform_get_irq(pdev, 0);
> > -   if (data->irq <= 0) {
> > -   dev_err(>dev, "failed to get irq\n");
> > -   return -ENODEV;
> > -   }
> -
> >     data->ipg_clk = devm_clk_get(>dev, "ipg");
> >     if (IS_ERR(data->ipg_clk)) {
> >     ret = PTR_ERR(data->ipg_clk);
> @@ -146,11 +164,17 @@ static int imx_irqsteer_probe(struct platform_device 
> *pdev)
>  
> >     raw_spin_lock_init(>lock);
>  
> > -   of_property_read_u32(np, "fsl,num-irqs", >reg_num);
> > +   of_property_read_u32(np, "fsl,num-irqs", _num);
> >     of_property_read_u32(np, "fsl,channel", >channel);
>  
> > -   /* one register bit map represents 32 input interrupts */
> > -   data->reg_num /= 32;
> > +   /*
> +  * There is one output irqs for each group of 64 inputs.

"irq", singular.

> +  * One register bit map can represent 32 input interrupts.
> > +    */
> > +   data->irq_count = irqs_num / 64;
> > +   if (irqs_num % 64)
> + data->irq_count += 1;

This is a 

[PATCH V2 4/4] irq: imx: irqsteer: add multi output interrupts support

2019-01-30 Thread Aisheng Dong
One irqsteer channel can support up to 8 output interrupts.

Cc: Marc Zyngier 
Cc: Lucas Stach 
Cc: Shawn Guo 
Signed-off-by: Dong Aisheng 
---
ChangeLog:
v1->v2:
 * calculate irq_count by fsl,num-irqs instead of parsing interrupts
   property from devicetree to match the input interrupts and outputs
 * improve output interrupt handler by searching only two registers
   withint the same group
---
 drivers/irqchip/irq-imx-irqsteer.c | 76 +-
 1 file changed, 59 insertions(+), 17 deletions(-)

diff --git a/drivers/irqchip/irq-imx-irqsteer.c 
b/drivers/irqchip/irq-imx-irqsteer.c
index 67ed862..cc40039 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -21,10 +22,13 @@
 #define CHAN_MINTDIS(t)(CTRL_STRIDE_OFF(t, 3) + 0x4)
 #define CHAN_MASTRSTAT(t)  (CTRL_STRIDE_OFF(t, 3) + 0x8)
 
+#define CHAN_MAX_OUTPUT_INT0x8
+
 struct irqsteer_data {
void __iomem*regs;
struct clk  *ipg_clk;
-   int irq;
+   int irq[CHAN_MAX_OUTPUT_INT];
+   int irq_count;
raw_spinlock_t  lock;
int reg_num;
int channel;
@@ -87,26 +91,45 @@ static const struct irq_domain_ops imx_irqsteer_domain_ops 
= {
.xlate  = irq_domain_xlate_onecell,
 };
 
+static int imx_irqsteer_get_hwirq_base(struct irqsteer_data *data, u32 irq)
+{
+   int i;
+
+   for (i = 0; i < data->irq_count; i++) {
+   if (data->irq[i] == irq)
+   break;
+   }
+
+   return i * 64;
+}
+
 static void imx_irqsteer_irq_handler(struct irq_desc *desc)
 {
struct irqsteer_data *data = irq_desc_get_handler_data(desc);
+   int hwirq;
int i;
 
chained_irq_enter(irq_desc_get_chip(desc), desc);
 
-   for (i = 0; i < data->reg_num * 32; i += 32) {
-   int idx = imx_irqsteer_get_reg_index(data, i);
+   hwirq = imx_irqsteer_get_hwirq_base(data, irq_desc_get_irq(desc));
+
+   for (i = 0; i < 2; i++) {
+   int idx = imx_irqsteer_get_reg_index(data, hwirq);
unsigned long irqmap;
int pos, virq;
 
+   if (hwirq >= data->reg_num * 32)
+   break;
+
irqmap = readl_relaxed(data->regs +
   CHANSTATUS(idx, data->reg_num));
 
for_each_set_bit(pos, , 32) {
-   virq = irq_find_mapping(data->domain, pos + i);
+   virq = irq_find_mapping(data->domain, pos + hwirq);
if (virq)
generic_handle_irq(virq);
}
+   hwirq += 32;
}
 
chained_irq_exit(irq_desc_get_chip(desc), desc);
@@ -117,7 +140,8 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct irqsteer_data *data;
struct resource *res;
-   int ret;
+   u32 irqs_num;
+   int i, ret;
 
data = devm_kzalloc(>dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -130,12 +154,6 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
return PTR_ERR(data->regs);
}
 
-   data->irq = platform_get_irq(pdev, 0);
-   if (data->irq <= 0) {
-   dev_err(>dev, "failed to get irq\n");
-   return -ENODEV;
-   }
-
data->ipg_clk = devm_clk_get(>dev, "ipg");
if (IS_ERR(data->ipg_clk)) {
ret = PTR_ERR(data->ipg_clk);
@@ -146,11 +164,17 @@ static int imx_irqsteer_probe(struct platform_device 
*pdev)
 
raw_spin_lock_init(>lock);
 
-   of_property_read_u32(np, "fsl,num-irqs", >reg_num);
+   of_property_read_u32(np, "fsl,num-irqs", _num);
of_property_read_u32(np, "fsl,channel", >channel);
 
-   /* one register bit map represents 32 input interrupts */
-   data->reg_num /= 32;
+   /*
+* There is one output irqs for each group of 64 inputs.
+* One register bit map can represent 32 input interrupts.
+*/
+   data->irq_count = irqs_num / 64;
+   if (irqs_num % 64)
+   data->irq_count += 1;
+   data->reg_num = irqs_num / 32;
 
if (IS_ENABLED(CONFIG_PM_SLEEP)) {
data->saved_reg = devm_kzalloc(>dev,
@@ -177,8 +201,22 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
return -ENOMEM;
}
 
-   irq_set_chained_handler_and_data(data->irq, imx_irqsteer_irq_handler,
-data);
+   if (!data->irq_count || data->irq_count > CHAN_MAX_OUTPUT_INT) {
+   clk_disable_unprepare(data->ipg_clk);
+   return -EINVAL;
+   }
+
+   for (i = 0; i