From patchwork Fri Mar 10 23:04:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ladislav Michl X-Patchwork-Id: 9618117 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 65216604D9 for ; Fri, 10 Mar 2017 23:04:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 56C4E287B7 for ; Fri, 10 Mar 2017 23:04:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 46CD3287BB; Fri, 10 Mar 2017 23:04:53 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B3628287B7 for ; Fri, 10 Mar 2017 23:04:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934111AbdCJXEv (ORCPT ); Fri, 10 Mar 2017 18:04:51 -0500 Received: from eddie.linux-mips.org ([148.251.95.138]:57978 "EHLO cvs.linux-mips.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934197AbdCJXEu (ORCPT ); Fri, 10 Mar 2017 18:04:50 -0500 Received: (from localhost user: 'ladis' uid#1021 fake: STDIN (ladis@eddie.linux-mips.org)) by eddie.linux-mips.org id S23993910AbdCJXEhmRytA (ORCPT ); Sat, 11 Mar 2017 00:04:37 +0100 Date: Sat, 11 Mar 2017 00:04:30 +0100 From: Ladislav Michl To: linux-omap@vger.kernel.org Subject: gpio-omap: Edge interrupts stall Message-ID: <20170310230430.6pfljo5rr7esn5qb@lenoch> MIME-Version: 1.0 Content-Disposition: inline User-Agent: NeoMutt/20170113 (1.7.2) Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Hi there, I'm using drivers/media/rc/gpio-ir-recv.c on DM3730 based board and getting a lot of IR protocol decoding failures: RC5(x/sz) decode failed at state 0 count 7 (855us space) RC5(x/sz) decode failed at state 1 count 4 (1740us space) RC5(x/sz) decode failed at state 4 count 1 (125000us space) RC5(x/sz) decode failed at state 0 count 1 (182348us space) RC5(x/sz) decode failed at state 0 count 1 (366us pulse) etc... Hacking gpio-ir-recv code to add debounce on GPIO pin makes situation a bit better, but still bad enough. It seems this problem is there since dawn of linux-omap time [1] and can be easily reproduced requesting edge trigerred gpio interrupt, feeding that gpio pin from signal generator and toggling another gpio in interrupt hangler with scope hooked. Last time patch [1] was updated to kernel 2.6.32 and you can find it below. So it seems noone is really using edge triggered interrupts, right? Now, patch bellow is for ancient omap1 variant (and I'd love to give it a try with recent kernel, but everything I compiled so far is insanely huge) and does not support both rising and falling edge. To make interrupt code reliable I do not see other option than to read gpio input register and make loop similar as in patch bellow. However, this was repeatedly rejected in the past. So, better ideas, anyone? Thank you, ladis [1] http://marc.info/?l=linux-omap&m=119634410025393&w=2 --- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html --- linux-2.6.32/arch/arm/plat-omap/gpio.c.orig 2009-12-29 20:56:29.000000000 +0100 +++ linux-2.6.32/arch/arm/plat-omap/gpio.c 2009-12-29 20:56:44.000000000 +0100 @@ -192,6 +192,7 @@ u32 saved_risingdetect; #endif u32 level_mask; + u32 serviced; spinlock_t lock; struct gpio_chip chip; struct clk *dbck; @@ -1204,6 +1205,28 @@ spin_unlock_irqrestore(&bank->lock, flags); } +static u32 _get_gpio_irq_status(struct gpio_bank *bank) +{ + u32 isr, ism, in, re; + u32 base = bank->base; + + switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP15XX + case METHOD_GPIO_1510: + in = __raw_readl(base + OMAP1510_GPIO_DATA_INPUT); + isr = __raw_readl(base + OMAP1510_GPIO_INT_STATUS); + ism = __raw_readl(base + OMAP1510_GPIO_INT_MASK) | 0xffff0000; + re = __raw_readl(base + OMAP1510_GPIO_INT_CONTROL); + isr |= (~(in^re)) & (~ism); + break; +#endif + default: + BUG(); + return 0; + } + return isr; +} + /* * We need to unmask the GPIO bank interrupt as soon as possible to * avoid missing GPIO interrupts for other lines in the bank. @@ -1218,11 +1241,13 @@ void __iomem *isr_reg = NULL; u32 isr; unsigned int gpio_irq; + unsigned long flags; struct gpio_bank *bank; u32 retrigger = 0; int unmasked = 0; desc->chip->ack(irq); + desc->chip->unmask(irq); bank = get_irq_data(irq); #ifdef CONFIG_ARCH_OMAP1 @@ -1249,54 +1274,29 @@ if (bank->method == METHOD_GPIO_24XX) isr_reg = bank->base + OMAP4_GPIO_IRQSTATUS0; #endif + spin_lock_irqsave(&bank->lock, flags); while(1) { - u32 isr_saved, level_mask = 0; - u32 enabled; + u32 isr; + unsigned long serviced; - enabled = _get_gpio_irqbank_mask(bank); - isr_saved = isr = __raw_readl(isr_reg) & enabled; - - if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO)) - isr &= 0x0000ffff; - - if (cpu_class_is_omap2()) { - level_mask = bank->level_mask & enabled; - } - - /* clear edge sensitive interrupts before handler(s) are - called so that we don't miss any interrupt occurred while - executing them */ - _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 0); - _clear_gpio_irqbank(bank, isr_saved & ~level_mask); - _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 1); - - /* if there is only edge sensitive GPIO pin interrupts - configured, we could unmask GPIO bank interrupt immediately */ - if (!level_mask && !unmasked) { - unmasked = 1; - desc->chip->unmask(irq); - } - - isr |= retrigger; - retrigger = 0; + isr = _get_gpio_irq_status(bank) & ~bank->serviced; if (!isr) break; gpio_irq = bank->virtual_irq_start; - for (; isr != 0; isr >>= 1, gpio_irq++) { - if (!(isr & 1)) - continue; - - generic_handle_irq(gpio_irq); + serviced = 1; + for (; isr != 0; gpio_irq++, serviced <<= 1 ) { + if (isr & serviced) { + bank->serviced |= serviced; + spin_unlock_irqrestore(&bank->lock, flags); + generic_handle_irq(gpio_irq); + spin_lock_irqsave(&bank->lock, flags); + bank->serviced &= ~serviced; + isr &= ~serviced; + } } } - /* if bank has any level sensitive GPIO pin interrupt - configured, we must unmask the bank interrupt only after - handler(s) are executed in order to avoid spurious bank - interrupt */ - if (!unmasked) - desc->chip->unmask(irq); - + spin_unlock_irqrestore(&bank->lock, flags); } static void gpio_irq_shutdown(unsigned int irq) @@ -1781,6 +1781,7 @@ #endif bank->mod_usage = 0; + bank->serviced = 0; /* REVISIT eventually switch from OMAP-specific gpio structs * over to the generic ones */