From: Ludovic BARRE <ludovic.barre@st.com> To: Marc Zyngier <marc.zyngier@arm.com>, Thomas Gleixner <tglx@linutronix.de>, Jason Cooper <jason@lakedaemon.net> Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>, Alexandre Torgue <alexandre.torgue@st.com>, <linux-kernel@vger.kernel.org>, <linux-arm-kernel@lists.infradead.org> Subject: Re: [PATCH 2/8] irqchip: stm32: add multi-bank management Date: Tue, 8 Aug 2017 11:28:24 +0200 [thread overview] Message-ID: <cb1943ea-1ca9-3a90-252c-d11b9de11b03@st.com> (raw) In-Reply-To: <1d693fee-2804-01ec-f0a6-ef5ca1854b46@arm.com> hi Marc sorry for previous message in html (recently, I've changed my laptop and forgot my setup for plain text) :-( On 08/07/2017 03:21 PM, Marc Zyngier wrote: > On 07/07/17 08:26, Ludovic Barre wrote: >> From: Ludovic Barre <ludovic.barre@st.com> >> >> -prepare to manage multi-bank >> -prepare to manage registers offset by compatible >> >> Signed-off-by: Ludovic Barre <ludovic.barre@st.com> >> --- >> drivers/irqchip/irq-stm32-exti.c | 137 ++++++++++++++++++++++++++------------- >> 1 file changed, 91 insertions(+), 46 deletions(-) >> >> diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c >> index 491568c..308cef5 100644 >> --- a/drivers/irqchip/irq-stm32-exti.c >> +++ b/drivers/irqchip/irq-stm32-exti.c >> @@ -14,27 +14,52 @@ >> #include <linux/of_address.h> >> #include <linux/of_irq.h> >> >> -#define EXTI_IMR 0x0 >> -#define EXTI_EMR 0x4 >> -#define EXTI_RTSR 0x8 >> -#define EXTI_FTSR 0xc >> -#define EXTI_SWIER 0x10 >> -#define EXTI_PR 0x14 >> +struct stm32_exti_bank { >> + u32 imr_ofst; >> + u32 emr_ofst; >> + u32 rtsr_ofst; >> + u32 ftsr_ofst; >> + u32 swier_ofst; >> + u32 pr_ofst; >> + >> + u32 irqs_mask; >> +}; > > This looks weird. On one hand, you have a set of offsets that are > typical of the HW, and yet you add to it a mask that is read from the HW > (and not hardcoded like the rest). oops, It is a residue, (set in probe but not used) So, I will remove irqs_mask, and adds a const > >> + >> +static struct stm32_exti_bank stm32f4xx_exti_b1 = { >> + .imr_ofst = 0x00, >> + .emr_ofst = 0x04, >> + .rtsr_ofst = 0x08, >> + .ftsr_ofst = 0x0C, >> + .swier_ofst = 0x10, >> + .pr_ofst = 0x14, >> +}; > > And this prevents making this structure const, which it should be. > >> + >> +static struct stm32_exti_bank *stm32f4xx_exti_banks[] = { >> + &stm32f4xx_exti_b1, >> +}; >> >> static void stm32_irq_handler(struct irq_desc *desc) >> { >> struct irq_domain *domain = irq_desc_get_handler_data(desc); >> - struct irq_chip_generic *gc = domain->gc->gc[0]; >> struct irq_chip *chip = irq_desc_get_chip(desc); >> + unsigned int virq, nbanks = domain->gc->num_chips; >> + struct irq_chip_generic *gc; >> + struct stm32_exti_bank *stm32_bank; >> unsigned long pending; >> - int n; >> + int n, i, irq_base = 0; >> >> chained_irq_enter(chip, desc); >> >> - while ((pending = irq_reg_readl(gc, EXTI_PR))) { >> - for_each_set_bit(n, &pending, BITS_PER_LONG) { >> - generic_handle_irq(irq_find_mapping(domain, n)); >> - irq_reg_writel(gc, BIT(n), EXTI_PR); >> + for (i = 0; i < nbanks; i++, irq_base += BITS_PER_LONG) { > > Are you guaranteed that all the interrupts are organised in a linear > way? No hole between them? Ever? currently, Exti could manage up to N linear input events distributed in X banks of 32 events. example H7 has 96 events => 3*32 There is no hole between the bank, but some inputs may not be connected (hardware design choice). > >> + gc = irq_get_domain_generic_chip(domain, irq_base); >> + stm32_bank = gc->private; >> + >> + while ((pending = irq_reg_readl(gc, stm32_bank->pr_ofst))) { >> + for_each_set_bit(n, &pending, BITS_PER_LONG) { >> + virq = irq_find_mapping(domain, irq_base + n); >> + generic_handle_irq(virq); >> + irq_reg_writel(gc, BIT(n), stm32_bank->pr_ofst); > > This code doesn't look very good. Since you already have the bank as > part of your gc structure, why don't you add a set of wrappers such as: > > static void stm32_irq_write_pr(struct irq_chip_generic *gc, u32 val) > { > struct stm32_exti_bank *bank = gc->private; > irq_reg_writel(gc, val, bank->pr_ofst); > } > > Nobody really want to know about this offset business, so just hide it > as much as possible. yes, you're right. I will create a "stm32_exti_pending" and "stm32_exti_irq_ack" functions > >> + } >> } >> } >> >> @@ -44,13 +69,14 @@ static void stm32_irq_handler(struct irq_desc *desc) >> static int stm32_irq_set_type(struct irq_data *data, unsigned int type) >> { >> struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); >> - int pin = data->hwirq; >> + struct stm32_exti_bank *stm32_bank = gc->private; >> + int pin = data->hwirq % BITS_PER_LONG; >> u32 rtsr, ftsr; >> >> irq_gc_lock(gc); >> >> - rtsr = irq_reg_readl(gc, EXTI_RTSR); >> - ftsr = irq_reg_readl(gc, EXTI_FTSR); >> + rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); >> + ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); >> >> switch (type) { >> case IRQ_TYPE_EDGE_RISING: >> @@ -70,8 +96,8 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) >> return -EINVAL; >> } >> >> - irq_reg_writel(gc, rtsr, EXTI_RTSR); >> - irq_reg_writel(gc, ftsr, EXTI_FTSR); >> + irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst); >> + irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); >> >> irq_gc_unlock(gc); >> >> @@ -81,17 +107,18 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) >> static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) >> { >> struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); >> - int pin = data->hwirq; >> + struct stm32_exti_bank *stm32_bank = gc->private; >> + int pin = data->hwirq % BITS_PER_LONG; >> u32 emr; >> >> irq_gc_lock(gc); >> >> - emr = irq_reg_readl(gc, EXTI_EMR); >> + emr = irq_reg_readl(gc, stm32_bank->emr_ofst); >> if (on) >> emr |= BIT(pin); >> else >> emr &= ~BIT(pin); >> - irq_reg_writel(gc, emr, EXTI_EMR); >> + irq_reg_writel(gc, emr, stm32_bank->emr_ofst); >> >> irq_gc_unlock(gc); >> >> @@ -101,11 +128,12 @@ static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) >> static int stm32_exti_alloc(struct irq_domain *d, unsigned int virq, >> unsigned int nr_irqs, void *data) >> { >> - struct irq_chip_generic *gc = d->gc->gc[0]; >> + struct irq_chip_generic *gc; >> struct irq_fwspec *fwspec = data; >> irq_hw_number_t hwirq; >> >> hwirq = fwspec->param[0]; >> + gc = irq_get_domain_generic_chip(d, hwirq); >> >> irq_map_generic_chip(d, virq, hwirq); >> irq_domain_set_info(d, virq, hwirq, &gc->chip_types->chip, gc, >> @@ -129,8 +157,8 @@ struct irq_domain_ops irq_exti_domain_ops = { >> .free = stm32_exti_free, >> }; >> >> -static int __init stm32_exti_init(struct device_node *node, >> - struct device_node *parent) >> +static int __init stm32_exti_init(struct stm32_exti_bank **stm32_exti_banks, >> + int bank_nr, struct device_node *node) >> { >> unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; >> int nr_irqs, nr_exti, ret, i; >> @@ -144,23 +172,16 @@ static int __init stm32_exti_init(struct device_node *node, >> return -ENOMEM; >> } >> >> - /* Determine number of irqs supported */ >> - writel_relaxed(~0UL, base + EXTI_RTSR); >> - nr_exti = fls(readl_relaxed(base + EXTI_RTSR)); >> - writel_relaxed(0, base + EXTI_RTSR); >> - >> - pr_info("%s: %d External IRQs detected\n", node->full_name, nr_exti); >> - >> - domain = irq_domain_add_linear(node, nr_exti, >> + domain = irq_domain_add_linear(node, bank_nr * BITS_PER_LONG, > > You used to size the domain with the number of *implemented* interrupts. > Now, it becomes something else. Why is that so? when there was only 32 events we could use number of implemented event, anyway the 32 events was parsed in stm32_irq_handler. Today the irq number allow to look up the appropriate bank Also, is BITS_PER_LONG > the right macro? Shouldn't it be something like "IRQS_PER_BANK", or > something similar? Just in case someone recycles this block on a 64bit > CPU... I just reuse "BITS_PER_LONG" used in stm32_irq_handler. But yes, that make sense to change to IRQS_PER_BANK. > >> &irq_exti_domain_ops, NULL); >> if (!domain) { >> pr_err("%s: Could not register interrupt domain.\n", >> - node->name); >> + node->name); >> ret = -ENOMEM; >> goto out_unmap; >> } >> >> - ret = irq_alloc_domain_generic_chips(domain, nr_exti, 1, "exti", >> + ret = irq_alloc_domain_generic_chips(domain, BITS_PER_LONG, 1, "exti", > > And here, you're not multiplying it by the number of banks. Why? The goal is to create one domain with "bank_nr" generic chips (for stm32 h7: 1 domain with 3 gc). irq_alloc_domain_generic_chips funtion set dgc->num_chips = irqs_per_chip / domain size. like this, each gc match with a bank (each gc has bank specification in gc->private = stm32_bank_N). irq_get_domain_generic_chip allow to look up bank specification with "irq number" (see stm32_irq_handler). I'm inspired of irq-atmel-aic-common.c or irq-bcm7120-l2c > >> handle_edge_irq, clr, 0, 0); >> if (ret) { >> pr_err("%s: Could not allocate generic interrupt chip.\n", >> @@ -168,18 +189,35 @@ static int __init stm32_exti_init(struct device_node *node, >> goto out_free_domain; >> } >> >> - gc = domain->gc->gc[0]; >> - gc->reg_base = base; >> - gc->chip_types->type = IRQ_TYPE_EDGE_BOTH; >> - gc->chip_types->chip.name = gc->chip_types[0].chip.name; >> - gc->chip_types->chip.irq_ack = irq_gc_ack_set_bit; >> - gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit; >> - gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit; >> - gc->chip_types->chip.irq_set_type = stm32_irq_set_type; >> - gc->chip_types->chip.irq_set_wake = stm32_irq_set_wake; >> - gc->chip_types->regs.ack = EXTI_PR; >> - gc->chip_types->regs.mask = EXTI_IMR; >> - gc->chip_types->handler = handle_edge_irq; >> + for (i = 0; i < bank_nr; i++) { >> + struct stm32_exti_bank *stm32_bank = stm32_exti_banks[i]; >> + u32 irqs_mask; >> + >> + gc = irq_get_domain_generic_chip(domain, i * BITS_PER_LONG); >> + >> + gc->reg_base = base; >> + gc->chip_types->type = IRQ_TYPE_EDGE_BOTH; >> + gc->chip_types->chip.name = gc->chip_types[0].chip.name; >> + gc->chip_types->chip.irq_ack = irq_gc_ack_set_bit; >> + gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit; >> + gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit; >> + gc->chip_types->chip.irq_set_type = stm32_irq_set_type; >> + gc->chip_types->chip.irq_set_wake = stm32_irq_set_wake; >> + gc->chip_types->regs.ack = stm32_bank->pr_ofst; >> + gc->chip_types->regs.mask = stm32_bank->imr_ofst; >> + gc->chip_types->handler = handle_edge_irq; >> + gc->private = stm32_bank; >> + >> + /* Determine number of irqs supported */ >> + writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); >> + irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); >> + stm32_bank->irqs_mask = irqs_mask; >> + nr_exti = fls(readl_relaxed(base + stm32_bank->rtsr_ofst)); >> + writel_relaxed(0, base + stm32_bank->rtsr_ofst); >> + >> + pr_info("%s: bank%d, External IRQs available:%#x\n", >> + node->full_name, i, irqs_mask); >> + } >> >> nr_irqs = of_irq_count(node); >> for (i = 0; i < nr_irqs; i++) { >> @@ -198,4 +236,11 @@ static int __init stm32_exti_init(struct device_node *node, >> return ret; >> } >> >> -IRQCHIP_DECLARE(stm32_exti, "st,stm32-exti", stm32_exti_init); >> +static int __init stm32f4_exti_of_init(struct device_node *np, >> + struct device_node *parent) >> +{ >> + return stm32_exti_init(stm32f4xx_exti_banks, >> + ARRAY_SIZE(stm32f4xx_exti_banks), np); >> +} >> + >> +IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init); >> > > Thanks, > > M. > BR Ludo
WARNING: multiple messages have this Message-ID (diff)
From: ludovic.barre@st.com (Ludovic BARRE) To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 2/8] irqchip: stm32: add multi-bank management Date: Tue, 8 Aug 2017 11:28:24 +0200 [thread overview] Message-ID: <cb1943ea-1ca9-3a90-252c-d11b9de11b03@st.com> (raw) In-Reply-To: <1d693fee-2804-01ec-f0a6-ef5ca1854b46@arm.com> hi Marc sorry for previous message in html (recently, I've changed my laptop and forgot my setup for plain text) :-( On 08/07/2017 03:21 PM, Marc Zyngier wrote: > On 07/07/17 08:26, Ludovic Barre wrote: >> From: Ludovic Barre <ludovic.barre@st.com> >> >> -prepare to manage multi-bank >> -prepare to manage registers offset by compatible >> >> Signed-off-by: Ludovic Barre <ludovic.barre@st.com> >> --- >> drivers/irqchip/irq-stm32-exti.c | 137 ++++++++++++++++++++++++++------------- >> 1 file changed, 91 insertions(+), 46 deletions(-) >> >> diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c >> index 491568c..308cef5 100644 >> --- a/drivers/irqchip/irq-stm32-exti.c >> +++ b/drivers/irqchip/irq-stm32-exti.c >> @@ -14,27 +14,52 @@ >> #include <linux/of_address.h> >> #include <linux/of_irq.h> >> >> -#define EXTI_IMR 0x0 >> -#define EXTI_EMR 0x4 >> -#define EXTI_RTSR 0x8 >> -#define EXTI_FTSR 0xc >> -#define EXTI_SWIER 0x10 >> -#define EXTI_PR 0x14 >> +struct stm32_exti_bank { >> + u32 imr_ofst; >> + u32 emr_ofst; >> + u32 rtsr_ofst; >> + u32 ftsr_ofst; >> + u32 swier_ofst; >> + u32 pr_ofst; >> + >> + u32 irqs_mask; >> +}; > > This looks weird. On one hand, you have a set of offsets that are > typical of the HW, and yet you add to it a mask that is read from the HW > (and not hardcoded like the rest). oops, It is a residue, (set in probe but not used) So, I will remove irqs_mask, and adds a const > >> + >> +static struct stm32_exti_bank stm32f4xx_exti_b1 = { >> + .imr_ofst = 0x00, >> + .emr_ofst = 0x04, >> + .rtsr_ofst = 0x08, >> + .ftsr_ofst = 0x0C, >> + .swier_ofst = 0x10, >> + .pr_ofst = 0x14, >> +}; > > And this prevents making this structure const, which it should be. > >> + >> +static struct stm32_exti_bank *stm32f4xx_exti_banks[] = { >> + &stm32f4xx_exti_b1, >> +}; >> >> static void stm32_irq_handler(struct irq_desc *desc) >> { >> struct irq_domain *domain = irq_desc_get_handler_data(desc); >> - struct irq_chip_generic *gc = domain->gc->gc[0]; >> struct irq_chip *chip = irq_desc_get_chip(desc); >> + unsigned int virq, nbanks = domain->gc->num_chips; >> + struct irq_chip_generic *gc; >> + struct stm32_exti_bank *stm32_bank; >> unsigned long pending; >> - int n; >> + int n, i, irq_base = 0; >> >> chained_irq_enter(chip, desc); >> >> - while ((pending = irq_reg_readl(gc, EXTI_PR))) { >> - for_each_set_bit(n, &pending, BITS_PER_LONG) { >> - generic_handle_irq(irq_find_mapping(domain, n)); >> - irq_reg_writel(gc, BIT(n), EXTI_PR); >> + for (i = 0; i < nbanks; i++, irq_base += BITS_PER_LONG) { > > Are you guaranteed that all the interrupts are organised in a linear > way? No hole between them? Ever? currently, Exti could manage up to N linear input events distributed in X banks of 32 events. example H7 has 96 events => 3*32 There is no hole between the bank, but some inputs may not be connected (hardware design choice). > >> + gc = irq_get_domain_generic_chip(domain, irq_base); >> + stm32_bank = gc->private; >> + >> + while ((pending = irq_reg_readl(gc, stm32_bank->pr_ofst))) { >> + for_each_set_bit(n, &pending, BITS_PER_LONG) { >> + virq = irq_find_mapping(domain, irq_base + n); >> + generic_handle_irq(virq); >> + irq_reg_writel(gc, BIT(n), stm32_bank->pr_ofst); > > This code doesn't look very good. Since you already have the bank as > part of your gc structure, why don't you add a set of wrappers such as: > > static void stm32_irq_write_pr(struct irq_chip_generic *gc, u32 val) > { > struct stm32_exti_bank *bank = gc->private; > irq_reg_writel(gc, val, bank->pr_ofst); > } > > Nobody really want to know about this offset business, so just hide it > as much as possible. yes, you're right. I will create a "stm32_exti_pending" and "stm32_exti_irq_ack" functions > >> + } >> } >> } >> >> @@ -44,13 +69,14 @@ static void stm32_irq_handler(struct irq_desc *desc) >> static int stm32_irq_set_type(struct irq_data *data, unsigned int type) >> { >> struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); >> - int pin = data->hwirq; >> + struct stm32_exti_bank *stm32_bank = gc->private; >> + int pin = data->hwirq % BITS_PER_LONG; >> u32 rtsr, ftsr; >> >> irq_gc_lock(gc); >> >> - rtsr = irq_reg_readl(gc, EXTI_RTSR); >> - ftsr = irq_reg_readl(gc, EXTI_FTSR); >> + rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); >> + ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); >> >> switch (type) { >> case IRQ_TYPE_EDGE_RISING: >> @@ -70,8 +96,8 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) >> return -EINVAL; >> } >> >> - irq_reg_writel(gc, rtsr, EXTI_RTSR); >> - irq_reg_writel(gc, ftsr, EXTI_FTSR); >> + irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst); >> + irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); >> >> irq_gc_unlock(gc); >> >> @@ -81,17 +107,18 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) >> static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) >> { >> struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); >> - int pin = data->hwirq; >> + struct stm32_exti_bank *stm32_bank = gc->private; >> + int pin = data->hwirq % BITS_PER_LONG; >> u32 emr; >> >> irq_gc_lock(gc); >> >> - emr = irq_reg_readl(gc, EXTI_EMR); >> + emr = irq_reg_readl(gc, stm32_bank->emr_ofst); >> if (on) >> emr |= BIT(pin); >> else >> emr &= ~BIT(pin); >> - irq_reg_writel(gc, emr, EXTI_EMR); >> + irq_reg_writel(gc, emr, stm32_bank->emr_ofst); >> >> irq_gc_unlock(gc); >> >> @@ -101,11 +128,12 @@ static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) >> static int stm32_exti_alloc(struct irq_domain *d, unsigned int virq, >> unsigned int nr_irqs, void *data) >> { >> - struct irq_chip_generic *gc = d->gc->gc[0]; >> + struct irq_chip_generic *gc; >> struct irq_fwspec *fwspec = data; >> irq_hw_number_t hwirq; >> >> hwirq = fwspec->param[0]; >> + gc = irq_get_domain_generic_chip(d, hwirq); >> >> irq_map_generic_chip(d, virq, hwirq); >> irq_domain_set_info(d, virq, hwirq, &gc->chip_types->chip, gc, >> @@ -129,8 +157,8 @@ struct irq_domain_ops irq_exti_domain_ops = { >> .free = stm32_exti_free, >> }; >> >> -static int __init stm32_exti_init(struct device_node *node, >> - struct device_node *parent) >> +static int __init stm32_exti_init(struct stm32_exti_bank **stm32_exti_banks, >> + int bank_nr, struct device_node *node) >> { >> unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; >> int nr_irqs, nr_exti, ret, i; >> @@ -144,23 +172,16 @@ static int __init stm32_exti_init(struct device_node *node, >> return -ENOMEM; >> } >> >> - /* Determine number of irqs supported */ >> - writel_relaxed(~0UL, base + EXTI_RTSR); >> - nr_exti = fls(readl_relaxed(base + EXTI_RTSR)); >> - writel_relaxed(0, base + EXTI_RTSR); >> - >> - pr_info("%s: %d External IRQs detected\n", node->full_name, nr_exti); >> - >> - domain = irq_domain_add_linear(node, nr_exti, >> + domain = irq_domain_add_linear(node, bank_nr * BITS_PER_LONG, > > You used to size the domain with the number of *implemented* interrupts. > Now, it becomes something else. Why is that so? when there was only 32 events we could use number of implemented event, anyway the 32 events was parsed in stm32_irq_handler. Today the irq number allow to look up the appropriate bank Also, is BITS_PER_LONG > the right macro? Shouldn't it be something like "IRQS_PER_BANK", or > something similar? Just in case someone recycles this block on a 64bit > CPU... I just reuse "BITS_PER_LONG" used in stm32_irq_handler. But yes, that make sense to change to IRQS_PER_BANK. > >> &irq_exti_domain_ops, NULL); >> if (!domain) { >> pr_err("%s: Could not register interrupt domain.\n", >> - node->name); >> + node->name); >> ret = -ENOMEM; >> goto out_unmap; >> } >> >> - ret = irq_alloc_domain_generic_chips(domain, nr_exti, 1, "exti", >> + ret = irq_alloc_domain_generic_chips(domain, BITS_PER_LONG, 1, "exti", > > And here, you're not multiplying it by the number of banks. Why? The goal is to create one domain with "bank_nr" generic chips (for stm32 h7: 1 domain with 3 gc). irq_alloc_domain_generic_chips funtion set dgc->num_chips = irqs_per_chip / domain size. like this, each gc match with a bank (each gc has bank specification in gc->private = stm32_bank_N). irq_get_domain_generic_chip allow to look up bank specification with "irq number" (see stm32_irq_handler). I'm inspired of irq-atmel-aic-common.c or irq-bcm7120-l2c > >> handle_edge_irq, clr, 0, 0); >> if (ret) { >> pr_err("%s: Could not allocate generic interrupt chip.\n", >> @@ -168,18 +189,35 @@ static int __init stm32_exti_init(struct device_node *node, >> goto out_free_domain; >> } >> >> - gc = domain->gc->gc[0]; >> - gc->reg_base = base; >> - gc->chip_types->type = IRQ_TYPE_EDGE_BOTH; >> - gc->chip_types->chip.name = gc->chip_types[0].chip.name; >> - gc->chip_types->chip.irq_ack = irq_gc_ack_set_bit; >> - gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit; >> - gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit; >> - gc->chip_types->chip.irq_set_type = stm32_irq_set_type; >> - gc->chip_types->chip.irq_set_wake = stm32_irq_set_wake; >> - gc->chip_types->regs.ack = EXTI_PR; >> - gc->chip_types->regs.mask = EXTI_IMR; >> - gc->chip_types->handler = handle_edge_irq; >> + for (i = 0; i < bank_nr; i++) { >> + struct stm32_exti_bank *stm32_bank = stm32_exti_banks[i]; >> + u32 irqs_mask; >> + >> + gc = irq_get_domain_generic_chip(domain, i * BITS_PER_LONG); >> + >> + gc->reg_base = base; >> + gc->chip_types->type = IRQ_TYPE_EDGE_BOTH; >> + gc->chip_types->chip.name = gc->chip_types[0].chip.name; >> + gc->chip_types->chip.irq_ack = irq_gc_ack_set_bit; >> + gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit; >> + gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit; >> + gc->chip_types->chip.irq_set_type = stm32_irq_set_type; >> + gc->chip_types->chip.irq_set_wake = stm32_irq_set_wake; >> + gc->chip_types->regs.ack = stm32_bank->pr_ofst; >> + gc->chip_types->regs.mask = stm32_bank->imr_ofst; >> + gc->chip_types->handler = handle_edge_irq; >> + gc->private = stm32_bank; >> + >> + /* Determine number of irqs supported */ >> + writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); >> + irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); >> + stm32_bank->irqs_mask = irqs_mask; >> + nr_exti = fls(readl_relaxed(base + stm32_bank->rtsr_ofst)); >> + writel_relaxed(0, base + stm32_bank->rtsr_ofst); >> + >> + pr_info("%s: bank%d, External IRQs available:%#x\n", >> + node->full_name, i, irqs_mask); >> + } >> >> nr_irqs = of_irq_count(node); >> for (i = 0; i < nr_irqs; i++) { >> @@ -198,4 +236,11 @@ static int __init stm32_exti_init(struct device_node *node, >> return ret; >> } >> >> -IRQCHIP_DECLARE(stm32_exti, "st,stm32-exti", stm32_exti_init); >> +static int __init stm32f4_exti_of_init(struct device_node *np, >> + struct device_node *parent) >> +{ >> + return stm32_exti_init(stm32f4xx_exti_banks, >> + ARRAY_SIZE(stm32f4xx_exti_banks), np); >> +} >> + >> +IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init); >> > > Thanks, > > M. > BR Ludo
next prev parent reply other threads:[~2017-08-08 9:29 UTC|newest] Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top 2017-07-07 7:26 [PATCH 0/8] irqchip: stm32: add stm32h7 support Ludovic Barre 2017-07-07 7:26 ` Ludovic Barre 2017-07-07 7:26 ` [PATCH 1/8] irqchip: stm32: select GENERIC_IRQ_CHIP Ludovic Barre 2017-07-07 7:26 ` Ludovic Barre 2017-07-07 7:26 ` [PATCH 2/8] irqchip: stm32: add multi-bank management Ludovic Barre 2017-07-07 7:26 ` Ludovic Barre 2017-08-07 13:21 ` Marc Zyngier 2017-08-07 13:21 ` Marc Zyngier 2017-08-08 9:28 ` Ludovic BARRE [this message] 2017-08-08 9:28 ` Ludovic BARRE 2017-07-07 7:26 ` [PATCH 3/8] dt-bindings: interrupt-controllers: add compatible string for stm32h7 Ludovic Barre 2017-07-07 7:26 ` Ludovic Barre 2017-07-07 7:26 ` [PATCH 4/8] irqchip: stm32: add stm32h7 support Ludovic Barre 2017-07-07 7:26 ` Ludovic Barre 2017-07-07 7:26 ` [PATCH 5/8] irqchip: stm32: fix initial values Ludovic Barre 2017-07-07 7:26 ` Ludovic Barre 2017-07-07 7:26 ` [PATCH 6/8] irqchip: stm32: move the wakeup on interrupt mask Ludovic Barre 2017-07-07 7:26 ` Ludovic Barre 2017-07-07 7:26 ` [PATCH 7/8] ARM: dts: stm32: add exti support for stm32h743 Ludovic Barre 2017-07-07 7:26 ` Ludovic Barre 2017-07-07 7:26 ` [PATCH 8/8] ARM: dts: stm32: add support of exti on stm32h743 pinctrl Ludovic Barre 2017-07-07 7:26 ` Ludovic Barre 2017-07-07 8:16 ` Alexandre Torgue 2017-07-07 8:16 ` Alexandre Torgue
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=cb1943ea-1ca9-3a90-252c-d11b9de11b03@st.com \ --to=ludovic.barre@st.com \ --cc=alexandre.torgue@st.com \ --cc=jason@lakedaemon.net \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-kernel@vger.kernel.org \ --cc=marc.zyngier@arm.com \ --cc=mcoquelin.stm32@gmail.com \ --cc=tglx@linutronix.de \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.