From patchwork Mon Aug 8 16:22:45 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: adharmap@codeaurora.org X-Patchwork-Id: 1045722 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p78GNNNn003187 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 8 Aug 2011 16:23:49 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QqSbe-00027v-IB; Mon, 08 Aug 2011 16:23:10 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QqSbe-0002hi-3d; Mon, 08 Aug 2011 16:23:10 +0000 Received: from wolverine02.qualcomm.com ([199.106.114.251]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QqSbZ-0002hJ-Vm for linux-arm-kernel@lists.infradead.org; Mon, 08 Aug 2011 16:23:07 +0000 X-IronPort-AV: E=McAfee;i="5400,1158,6431"; a="108625798" Received: from pdmz-ns-mip.qualcomm.com (HELO mostmsg01.qualcomm.com) ([199.106.114.10]) by wolverine02.qualcomm.com with ESMTP/TLS/ADH-AES256-SHA; 08 Aug 2011 09:23:01 -0700 Received: from adharmap-linux.qualcomm.com (pdmz-snip-v218.qualcomm.com [192.168.218.1]) by mostmsg01.qualcomm.com (Postfix) with ESMTPA id AD0C210004D8; Mon, 8 Aug 2011 09:23:01 -0700 (PDT) From: Abhijeet Dharmapurikar To: tglx@linutronix.de, davidb@codeaurora.org Subject: [RFC PATCH] genirq: set pending flag for disabled level interrupt Date: Mon, 8 Aug 2011 09:22:45 -0700 Message-Id: <1312820566-5842-1-git-send-email-adharmap@codeaurora.org> X-Mailer: git-send-email 1.7.6 X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110808_122306_292696_FA6ADBBD X-CRM114-Status: GOOD ( 26.66 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [199.106.114.251 listed in list.dnswl.org] Cc: linux-arm-msm@vger.kernel.org, Abhijeet Dharmapurikar , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, Paul Mundt , Jonathan Cameron , dwalker@fifo99.com, Ingo Molnar , linux-arm-msm-owner@vger.kernel.org, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 08 Aug 2011 16:30:31 +0000 (UTC) For hardware which has no wakeup source configuration facility, it needs its wakeup interrupts unmasked. If a wakeup edge interrupt triggered while the system was suspending the edge flow handler marks it pending and masks the interrupt. The kernel checks pending flag on wakeup interrupts and aborts suspend if one is set. If a wakeup level interrupt triggered while the system was suspending the level flow handler masks the interrupt without setting the pending flag. Suspend won't be aborted. This is fine as it is expected that a level triggered interrupt will stay triggered and cause the system to resume. This however doesn't work on chips that don't have wakeup configuration in hardware because such chips need that interrupt unmasked for causing a resume. Address that shortcoming by making the level flow handler set the pending flag if a wakeup interrupt controlled by such a chip is triggered while it is suspended. Signed-off-by: Abhijeet Dharmapurikar --- If a level interrupt irq triggered right while the system was doing suspend_noirqs, the level flow handler will mask that interrupt and when the system went in to power collapse the interrupt controller did not wakeup the phone. The interrupt controller needs an interrupt triggered and masked to wakeup the phone - it does not have any wakeup interrupt configuration. The solution presented here is to mark that level triggered wakeup interrupt pending for chips with IRQCHIP_MASK_ON_SUSPEND. This will cause check_wakeup_irqs to abort suspend. Other solution would be to unmask such level interrupt in check_wakeup_irqs() but that seemed like I was expanding and complicating check_wakeup_irqs() duties - let me know if you think otherwise. Note that we cannot unmask the interrupt in the level flow handler, that will cause an interrupt storm. include/linux/irq.h | 4 +++- kernel/irq/chip.c | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index 87a06f3..0019385 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -332,7 +332,9 @@ struct irq_chip { * * IRQCHIP_SET_TYPE_MASKED: Mask before calling chip.irq_set_type() * IRQCHIP_EOI_IF_HANDLED: Only issue irq_eoi() when irq was handled - * IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path + * IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path, + * mark wakeup level interrupts pending + * if suspended and triggered * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks * when irq enabled */ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index d5a3009..0199871 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -339,9 +339,23 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) * If its disabled or no action available * keep it masked and get out of here */ - if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) + if (unlikely(!desc->action)) goto out_unlock; + if (irqd_irq_disabled(&desc->irq_data)) { + /* + * Hardware which has no wakeup source configuration facility, + * needs its wakeup interrupts unmasked and triggered to cause + * a wakeup. Since the interrupt will be masked, mark it pending + * if it were suspended so that suspend will be aborted later. + */ + if (desc->istate & IRQS_SUSPENDED && + irqd_is_wakeup_set(&desc->irq_data) && + irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND) + desc->istate |= IRQS_PENDING; + goto out_unlock; + } + handle_irq_event(desc); if (!irqd_irq_disabled(&desc->irq_data) && !(desc->istate & IRQS_ONESHOT))