From patchwork Mon Feb 9 11:38:08 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshihiro Shimoda X-Patchwork-Id: 6191 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n19BcJuR030011 for ; Mon, 9 Feb 2009 11:38:19 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754654AbZBILiS (ORCPT ); Mon, 9 Feb 2009 06:38:18 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1754731AbZBILiS (ORCPT ); Mon, 9 Feb 2009 06:38:18 -0500 Received: from mail.renesas.com ([202.234.163.13]:51005 "EHLO mail06.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754394AbZBILiR (ORCPT ); Mon, 9 Feb 2009 06:38:17 -0500 X-AuditID: ac14038a-0000000800001ca1-b9-499015a16c70 Received: from guardian03.idc.renesas.com ([172.20.8.202]) by mail06.idc.renesas.com (sendmail) with ESMTP id n19Bc9Ac014575; Mon, 9 Feb 2009 20:38:09 +0900 (JST) Received: (from root@localhost) by guardian03.idc.renesas.com with id n19Bc9V9021897; Mon, 9 Feb 2009 20:38:09 +0900 (JST) Received: from mta01.idc.renesas.com (localhost [127.0.0.1]) by mta01.idc.renesas.com with ESMTP id n19Bc9Ah007380; Mon, 9 Feb 2009 20:38:09 +0900 (JST) Received: from [172.30.8.157] by ims05.idc.renesas.com (Sendmail) with ESMTPA id <0KES0048TQZKYB@ims05.idc.renesas.com>; Mon, 09 Feb 2009 20:38:09 +0900 (JST) Date: Mon, 09 Feb 2009 20:38:08 +0900 From: Yoshihiro Shimoda Subject: [PATCH] sh: fix INTC group handling To: Paul Mundt Cc: linux-sh@vger.kernel.org Message-id: <499015A0.9060105@renesas.com> MIME-version: 1.0 Content-type: text/plain; charset=ISO-8859-1 Content-transfer-encoding: 7bit User-Agent: Thunderbird 2.0.0.14 (Windows/20080421) X-Brightmail-Tracker: AAAAAA== Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org 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 --- drivers/sh/intc.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 68 insertions(+), 3 deletions(-) diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 58d24c5..f1826d2 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -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)