[PATCH] iop13xx: workaround errata that causes uart interrupts to be missed
Russell King - ARM Linux
linux at arm.linux.org.uk
Thu Oct 29 15:12:21 EDT 2009
You need to cc Alan Cox and lkml on this.
On Thu, Oct 29, 2009 at 12:09:00PM -0700, Dan Williams wrote:
> Reading the uart iir register sometimes results in the interrupt being
> cleared without being reported. Use the the system interrupt pending
> register as a fallback.
>
> This converts locations in the code that only care about the interrupt
> pending bit to use the iir_int_status() macro.
>
> Signed-off-by: Dan Williams <dan.j.williams at intel.com>
> ---
> This patch has been sitting in the 'misc' branch of the xscaleiop tree
> in an un-mergeable form for quite a while [1]. I finally got fed up
> with forward porting it and would like to try to get this workaround
> upstream. There appears to be no maintainer for 8250.c, so not sure who
> should merge this. I can append it to the end of my next pull request
> for the iop queue...?
>
> Thanks,
> Dan
>
> [1]: http://git.kernel.org/?p=linux/kernel/git/djbw/xscaleiop.git;a=commitdiff;h=a7d124f5
>
> drivers/serial/8250.c | 36 +++++++++++++++++++++++++++++++++---
> 1 files changed, 33 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
> index b1ae774..c905860 100644
> --- a/drivers/serial/8250.c
> +++ b/drivers/serial/8250.c
> @@ -547,6 +547,36 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value)
> (up->port.serial_in(&(up)->port, (offset)))
> #define serial_out(up, offset, value) \
> (up->port.serial_out(&(up)->port, (offset), (value)))
> +
> +#ifndef CONFIG_ARCH_IOP13XX
> +#define iir_int_status(up) serial_in((up), UART_IIR)
> +#else
> +/* A silicon issue on IOP13XX causes IIR reads to return UART_IIR_NO_INT
> + * even if an interrupt is pending. Use the system interrupt pending
> + * register to check for servicing as a workaround.
> + */
> +#include <mach/irqs.h>
> +static unsigned int iir_int_status(struct uart_8250_port *up)
> +{
> + unsigned long membase = (unsigned long) up->port.membase;
> + unsigned long ipnd, iir;
> +
> + ipnd = read_intpnd_1();
> + iir = UART_IIR_NO_INT;
> + if (membase == IOP13XX_UART0_VIRT) {
> + if (ipnd & (1 << (IRQ_IOP13XX_UART0 - 32)))
> + iir &= ~UART_IIR_NO_INT;
> + } else if (membase == IOP13XX_UART1_VIRT) {
> + if (ipnd & (1 << (IRQ_IOP13XX_UART1 - 32)))
> + iir &= ~UART_IIR_NO_INT;
> + } else
> + BUG();
> + /* clear the interupt via the LSR */
> + mem_serial_in(&up->port, UART_LSR);
> + return iir;
> +}
> +#endif
> +
> /*
> * We used to support using pause I/O for certain machines. We
> * haven't supported this for a while, but just in case it's badly
> @@ -1572,7 +1602,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
>
> up = list_entry(l, struct uart_8250_port, list);
>
> - iir = serial_in(up, UART_IIR);
> + iir = iir_int_status(up);
> if (!(iir & UART_IIR_NO_INT)) {
> serial8250_handle_port(up);
>
> @@ -1732,7 +1762,7 @@ static void serial8250_timeout(unsigned long data)
> struct uart_8250_port *up = (struct uart_8250_port *)data;
> unsigned int iir;
>
> - iir = serial_in(up, UART_IIR);
> + iir = iir_int_status(up);
> if (!(iir & UART_IIR_NO_INT))
> serial8250_handle_port(up);
> mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout));
> @@ -1753,7 +1783,7 @@ static void serial8250_backup_timeout(unsigned long data)
> serial_out(up, UART_IER, 0);
> }
>
> - iir = serial_in(up, UART_IIR);
> + iir = iir_int_status(up);
>
> /*
> * This should be a safe test for anyone who doesn't trust the
>
>
More information about the linux-arm-kernel
mailing list