Re: gpio-omap: Edge interrupts stall

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

* Ladislav Michl <ladis@xxxxxxxxxxxxxx> [170310 15:06]:
> 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?

Interesting, adding Grygorii to cc as well.

> 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?

> [1] http://marc.info/?l=linux-omap&m=119634410025393&w=2

Oh that thing yeah I remember testing it too. If we don't have any
other options for edge interrupts I guess the loop is what we need to
do. If you have some experimental patch to play with against the
current mainline, please post it and I'll give it a try too.

Regards,

Tony

> --- 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
>  		 */
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux