sh: fix INTC group handling
PATCH 1/1 sh: fix INTC group handling
In a grouped interrupt such as DMAC of SH7785, there was the problem that a certain interrupt masked the other interrupts when it was masked.
Signed-off-by Yoshihiro Shimoda <[email protected]>
--- drivers/sh/intc.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 68 insertions(+), 3 deletions(-)
drivers/sh/intc.c +68 -3
@@ -39,6 +39,12 @@ struct intc_handle_int {unsigned long handle; }; +struct intc_groups_int { +unsigned long handle; +int irq[32 ]; +unsigned long enabled_bit; +}; +struct intc_desc_int {unsigned long *reg;#ifdef CONFIG_SMP
@@ -49,6 +55,9 @@ struct intc_desc_int {unsigned int nr_prio;struct intc_handle_int *sense;unsigned int nr_sense; +struct intc_groups_int *group; +int group_index[NR_IRQS ]; +unsigned long group_bit[NR_IRQS ];struct irq_chip chip; };
@@ -206,6 +215,9 @@ static inline void _intc_enable(unsigned int irq, unsigned long handle)unsigned long addr;unsigned int cpu; +if (d->group_bit[irq]) + d->group[d->group_index[irq]].enabled_bit |= d->group_bit[irq]; +for (cpu =0 ; cpu <SMP_NR (d,_INTC_ADDR_E (handle)); cpu++) { addr =INTC_REG (d,_INTC_ADDR_E (handle), cpu); intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
@@ -218,13 +230,21 @@ static void intc_enable(unsigned int irq)_intc_enable (irq, (unsigned long )get_irq_chip_data (irq)); } -static void intc_disable (unsigned int irq) +static void _intc_disable (unsigned int irq,int mask_ack) {struct intc_desc_int *d =get_intc_desc (irq);unsigned long handle = (unsigned long )get_irq_chip_data (irq);unsigned long addr;unsigned int cpu; +if (!mask_ack && d->group_bit[irq]) { +struct intc_groups_int *g = &d->group[d->group_index[irq]]; + + g->enabled_bit &= ~d->group_bit[irq]; +if (g->enabled_bit) +return ; + } +for (cpu =0 ; cpu <SMP_NR (d,_INTC_ADDR_D (handle)); cpu++) { addr =INTC_REG (d,_INTC_ADDR_D (handle), cpu); intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
@@ -232,6 +252,16 @@ static void intc_disable(unsigned int irq) } } +static void intc_disable (unsigned int irq) +{ +_intc_disable (irq,0 ); +} + +static void intc_disable_mask_ack (unsigned int irq) +{ +_intc_disable (irq,1 ); +} +#if defined(CONFIG_CPU_SH3 ) || defined(CONFIG_CPU_SH4A )static void intc_mask_ack (unsigned int irq) {
@@ -546,13 +576,38 @@ static unsigned int __init intc_sense_data(struct intc_desc *desc,return 0 ; } +static void __init intc_group_data (struct intc_desc *desc, +struct intc_desc_int *d, +int irq, +unsigned long handle) +{ +struct intc_group *g = desc->groups; +struct intc_groups_int *gi; +int i, j; + +for (i =0 ; g && i < desc->nr_groups; i++) { + gi = &d->group[i]; +if (!gi->handle || (gi->handle = handle)) { + gi->handle = handle; +for (j =0 ; j <ARRAY_SIZE (gi->irq); j++) { +if (!gi->irq[j]) { + gi->irq[j] = irq; + d->group_index[irq] = i; + d->group_bit[irq] =1 << j; +return ; + } + } + } + } +} +static void __init intc_register_irq (struct intc_desc *desc,struct intc_desc_int *d,intc_enum enum_id,unsigned int irq) {struct intc_handle_int *hp; -unsigned int data[2 ], primary; +unsigned int data[2 ], primary, groups;/* Prefer single interrupt source bitmap over other combinations: * 1. bitmap, single interrupt source
@@ -568,6 +623,10 @@ static void __init intc_register_irq(struct intc_desc *desc,if (!data[0 ] && data[1 ]) primary =1 ; + groups =0 ; +if (!data[primary]) + groups =1 ; + data[0 ] = data[0 ] ? data[0 ] :intc_mask_data (desc, d, enum_id,1 ); data[1 ] = data[1 ] ? data[1 ] :intc_prio_data (desc, d, enum_id,1 );
@@ -608,6 +667,9 @@ static void __init intc_register_irq(struct intc_desc *desc, d->nr_prio++; } +if (groups) +intc_group_data (desc, d, irq, data[primary]); +/* add irq to d->sense list if sense is available */ data[0 ] =intc_sense_data (desc, d, enum_id);if (data[0 ]) {
@@ -688,10 +750,13 @@ void __init register_intc_controller(struct intc_desc *desc) } } +if (desc->nr_groups) + d->group =alloc_bootmem (desc->nr_groups *sizeof (*d->group)); + d->chip.name = desc->name; d->chip.mask = intc_disable; d->chip.unmask = intc_enable; - d->chip.mask_ack = intc_disable; + d->chip.mask_ack = intc_disable_mask_ack; d->chip.set_type = intc_set_sense;#if defined(CONFIG_CPU_SH3 ) || defined(CONFIG_CPU_SH4A )
Signature · 1 line
1.5.5
Hi Shimoda-san,
Quoted 4 lines · Yoshihiro Shimoda
In a grouped interrupt such as DMAC of SH7785, there was the problem that a certain interrupt masked the other interrupts when it was masked.
Signed-off-by Yoshihiro Shimoda <[email protected]>
I'll NAK this patch for now, please have look at the following patch and see if it solves your problem:
http://patchwork.kernel.org/patch/6812/
Thank you!
/ magnus