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

Re: [Xen-devel] Problems after enabling rcv/xmit interrupts of ns16550 on OMAP5



On Jul 11, 2013, at 7:21 PM, Ian Campbell <ian.campbell@xxxxxxxxxx> wrote:

> On Thu, 2013-07-11 at 18:53 +0800, Chen Baozi wrote:
> 
>> Any ideas?
> 
> Nothing immediately springs to mind. Did you DT-enable the ns16550
> driver?
Yes, I think. The printk works well before init_postirq.

> 
> I did a quick hack and slash job to get it going on the cubieboard2,
> which I've pasted below (also needed io.h to actually implement the
> accessors). (Be kind, it obviously needs proper cleanup ;-))
> 
> Do you know if you are getting any interrupts at all? I'm wondering if
> maybe there is a storm?
I think "press 'd'" triggers to dump the debug info states that the console's 
interrupt works at a certain point?

> 
> Ian.
> 
> diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
> index e0c87bb..ed18b91 100644
> --- a/xen/drivers/char/ns16550.c
> +++ b/xen/drivers/char/ns16550.c
> @@ -19,7 +19,10 @@
> #include <xen/iocap.h>
> #include <xen/pci.h>
> #include <xen/pci_regs.h>
> +#include <xen/vmap.h>
> #include <asm/io.h>
> +#include <asm/early_printk.h>
> +#include <asm/device.h>
> #ifdef CONFIG_X86
> #include <asm/fixmap.h>
> #endif
> @@ -39,7 +42,8 @@ string_param("com2", opt_com2);
> 
> static struct ns16550 {
>     int baud, clock_hz, data_bits, parity, stop_bits, fifo_size, irq;
> -    unsigned long io_base;   /* I/O port or memory-mapped I/O address. */
> +    u64 io_base;   /* I/O port or memory-mapped I/O address. */
> +    u64 io_size;
>     char __iomem *remapped_io_base;  /* Remapped virtual address of MMIO. */
>     /* UART with IRQ line: interrupt-driven I/O. */
>     struct irqaction irqaction;
> @@ -56,6 +60,7 @@ static struct ns16550 {
>     u32 bar;
>     u16 cr;
>     u8 bar_idx;
> +    struct dt_irq dt_irq;
> } ns16550_com[2] = { { 0 } };
> 
> /* Register offsets */
> @@ -128,18 +133,20 @@ static struct ns16550 {
> #define RESUME_DELAY    MILLISECS(10)
> #define RESUME_RETRIES  100
> 
> +#define REG_SHIFT 2
> +
> static char ns_read_reg(struct ns16550 *uart, int reg)
> {
> -    if ( uart->remapped_io_base == NULL )
> -        return inb(uart->io_base + reg);
> -    return readb(uart->remapped_io_base + reg);
> +//    if ( uart->remapped_io_base == NULL )
> +//        return inb(uart->io_base + reg);
> +    return readl(uart->remapped_io_base + (reg<<REG_SHIFT));
> }
> 
> static void ns_write_reg(struct ns16550 *uart, int reg, char c)
> {
> -    if ( uart->remapped_io_base == NULL )
> -        return outb(c, uart->io_base + reg);
> -    writeb(c, uart->remapped_io_base + reg);
> +//    if ( uart->remapped_io_base == NULL )
> +//        return outb(c, uart->io_base + reg);
> +    writel(c, uart->remapped_io_base + (reg<<REG_SHIFT));
> }
> 
> static void ns16550_interrupt(
> @@ -214,6 +221,7 @@ static int ns16550_getc(struct serial_port *port, char 
> *pc)
>     return 1;
> }
> 
> +#if 0
> static void pci_serial_early_init(struct ns16550 *uart)
> {
>     if ( !uart->ps_bdf_enable || uart->io_base >= 0x10000 )
> @@ -231,6 +239,7 @@ static void pci_serial_early_init(struct ns16550 *uart)
>     pci_conf_write16(0, uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2],
>                      PCI_COMMAND, PCI_COMMAND_IO);
> }
> +#endif
> 
> static void ns16550_setup_preirq(struct ns16550 *uart)
> {
> @@ -239,7 +248,9 @@ static void ns16550_setup_preirq(struct ns16550 *uart)
> 
>     uart->intr_works = 0;
> 
> +#if 0
>     pci_serial_early_init(uart);
> +#endif
> 
>     lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | uart->parity;
> 
> @@ -260,7 +271,8 @@ static void ns16550_setup_preirq(struct ns16550 *uart)
>         /* Baud rate already set: read it out from the divisor latch. */
>         divisor  = ns_read_reg(uart, DLL);
>         divisor |= ns_read_reg(uart, DLM) << 8;
> -        uart->baud = uart->clock_hz / (divisor << 4);
> +        early_printk("divisor %d\n", divisor);
> +        //uart->baud = uart->clock_hz / (divisor << 4);
>     }
>     ns_write_reg(uart, LCR, lcr);
> 
> @@ -285,8 +297,10 @@ static void __init ns16550_init_preirq(struct 
> serial_port *port)
>         uart->remapped_io_base = (void __iomem *)fix_to_virt(idx);
>         uart->remapped_io_base += uart->io_base & ~PAGE_MASK;
> #else
> -        uart->remapped_io_base = (char *)ioremap(uart->io_base, 8);
> +        uart->remapped_io_base = ioremap_attr(uart->io_base, uart->io_size, 
> PAGE_HYPERVISOR_NOCACHE);
> +//        uart->remapped_io_base = (char *)ioremap(uart->io_base, 8);
> #endif
> +        early_printk("UART mapped at %p\n", uart->remapped_io_base);
>     }
> 
>     ns16550_setup_preirq(uart);
> @@ -326,23 +340,27 @@ static void __init ns16550_init_postirq(struct 
> serial_port *port)
> 
>     /* Calculate time to fill RX FIFO and/or empty TX FIFO for polling. */
>     bits = uart->data_bits + uart->stop_bits + !!uart->parity;
> -    uart->timeout_ms = max_t(
> -        unsigned int, 1, (bits * uart->fifo_size * 1000) / uart->baud);
> -
> +//    uart->timeout_ms = max_t(
> +//        unsigned int, 1, (bits * uart->fifo_size * 1000) / uart->baud);
> +    uart->timeout_ms = 1;
>     if ( uart->irq > 0 )
>     {
>         uart->irqaction.handler = ns16550_interrupt;
>         uart->irqaction.name    = "ns16550";
>         uart->irqaction.dev_id  = port;
> -        if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
> -            printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);
> +        //if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
> +        //    printk("ERROR: Failed to allocate ns16550 IRQ %d\n", 
> uart->irq);
> +        if ( (rc = setup_dt_irq(&uart->dt_irq, &uart->irqaction)) != 0 )
> +            printk("ERROR: Failed to allocate ns16550 DT IRQ.\n");
>     }
> 
>     ns16550_setup_postirq(uart);
> 
> +#if 0
>     if ( uart->bar || uart->ps_bdf_enable )
>         pci_hide_device(uart->ps_bdf[0], PCI_DEVFN(uart->ps_bdf[1],
>                                                    uart->ps_bdf[2]));
> +#endif
> }
> 
> static void ns16550_suspend(struct serial_port *port)
> @@ -351,13 +369,16 @@ static void ns16550_suspend(struct serial_port *port)
> 
>     stop_timer(&uart->timer);
> 
> +#if 0
>     if ( uart->bar )
>        uart->cr = pci_conf_read16(0, uart->ps_bdf[0], uart->ps_bdf[1],
>                                   uart->ps_bdf[2], PCI_COMMAND);
> +#endif
> }
> 
> static void _ns16550_resume(struct serial_port *port)
> {
> +#if 0
>     struct ns16550 *uart = port->uart;
> 
>     if ( uart->bar )
> @@ -367,6 +388,7 @@ static void _ns16550_resume(struct serial_port *port)
>        pci_conf_write16(0, uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2],
>                         PCI_COMMAND, uart->cr);
>     }
> +#endif
> 
>     ns16550_setup_preirq(port->uart);
>     ns16550_setup_postirq(port->uart);
> @@ -440,6 +462,12 @@ static int __init ns16550_irq(struct serial_port *port)
>     return ((uart->irq > 0) ? uart->irq : -1);
> }
> 
> +static const struct dt_irq __init *ns16550_dt_irq(struct serial_port *port)
> +{
> +    struct ns16550 *uart = port->uart;
> +    return &uart->dt_irq;
> +}
> +
> static struct uart_driver __read_mostly ns16550_driver = {
>     .init_preirq  = ns16550_init_preirq,
>     .init_postirq = ns16550_init_postirq,
> @@ -449,9 +477,13 @@ static struct uart_driver __read_mostly ns16550_driver = 
> {
>     .tx_ready     = ns16550_tx_ready,
>     .putc         = ns16550_putc,
>     .getc         = ns16550_getc,
> -    .irq          = ns16550_irq
> +    .irq          = ns16550_irq,
> +    .dt_irq_get   = ns16550_dt_irq,
> +
> };
> 
> +#if 0
> +
> static int __init parse_parity_char(int c)
> {
>     switch ( c )
> @@ -709,8 +741,78 @@ void __init ns16550_init(int index, struct 
> ns16550_defaults *defaults)
>     /* Default is no transmit FIFO. */
>     uart->fifo_size = 1;
> 
> -    ns16550_parse_port_config(uart, (index == 0) ? opt_com1 : opt_com2);
> +    /* Register with generic serial driver. */
> +    serial_register_uart(uart - ns16550_com, &ns16550_driver, uart);
> }
> +#endif
> +
> +#if 1
> +static int __init ns16550_uart_dt_init(struct dt_device_node *dev,
> +                                       const void *data)
> +{
> +    struct ns16550 *uart;
> +    int res;
> +
> +    early_printk("%s\n", __func__);
> +
> +    uart = &ns16550_com[0];
> +
> +    uart->baud      = BAUD_AUTO;//115200;
> +    uart->clock_hz  = UART_CLOCK_HZ;
> +    uart->data_bits = 8;
> +    uart->parity    = PARITY_NONE;
> +    uart->stop_bits = 1;
> +    //uart->irq       = defaults->irq;
> +    //uart->io_base   = defaults->io_base;
> +    /* Default is no transmit FIFO. */
> +    uart->fifo_size = 1;
> +
> +    res = dt_device_get_address(dev, 0, &uart->io_base, &uart->io_size);
> +    if ( res )
> +    {
> +        early_printk("ns16550: Unable to retrieve the base"
> +                     " address of the UART\n");
> +        return res;
> +    }
> +
> +    early_printk("ns16550 at %"PRIx64"-%"PRIx64"\n", uart->io_base, 
> uart->io_base + uart->io_size);
> +
> +//    uart->io_base = addr; //ioremap_attr(addr, size, 
> PAGE_HYPERVISOR_NOCACHE);
> +//    if ( !uart->io_base )
> +//    {
> +//        early_printk("ns16550: Unable to map the UART memory\n");
> +//
> +//        return -ENOMEM;
> +//    }
> +
> +    res = dt_device_get_irq(dev, 0, &uart->dt_irq);
> +    if ( res )
> +    {
> +        early_printk("ns16550: Unable to retrieve the IRQ\n");
> +        return res;
> +    }
> +
> +    /* Register with generic serial driver. */
> +    serial_register_uart(uart - ns16550_com, &ns16550_driver, uart);
> +
> +    dt_device_set_used_by(dev, DOMID_XEN);
> +
> +    early_printk("console done?\n");
> +    printk("normal printk\n");
> +    return 0;
> +}
> +
> +static const char const *ns16550_dt_compat[] __initdata =
> +{
> +    "snps,dw-apb-uart",
> +    NULL
> +};
> +
> +DT_DEVICE_START(ns16550, "NS16550 UART", DEVICE_SERIAL)
> +        .compatible = ns16550_dt_compat,
> +        .init = ns16550_uart_dt_init,
> +DT_DEVICE_END
> +#endif
> 
> /*
>  * Local variables:
> diff --git a/xen/include/asm-arm/io.h b/xen/include/asm-arm/io.h
> index aea5233..170263f 100644
> --- a/xen/include/asm-arm/io.h
> +++ b/xen/include/asm-arm/io.h
> @@ -1,6 +1,54 @@
> #ifndef _ASM_IO_H
> #define _ASM_IO_H
> 
> +static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
> +{
> +        asm volatile("strb %1, %0"
> +                     : "+Qo" (*(volatile u8 __force *)addr)
> +                     : "r" (val));
> +}
> +
> +static inline void __raw_writel(u32 val, volatile void __iomem *addr)
> +{
> +        asm volatile("str %1, %0"
> +                     : "+Qo" (*(volatile u32 __force *)addr)
> +                     : "r" (val));
> +}
> +
> +static inline u8 __raw_readb(const volatile void __iomem *addr)
> +{
> +        u8 val;
> +        asm volatile("ldrb %1, %0"
> +                     : "+Qo" (*(volatile u8 __force *)addr),
> +                       "=r" (val));
> +        return val;
> +}
> +
> +static inline u32 __raw_readl(const volatile void __iomem *addr)
> +{
> +        u32 val;
> +        asm volatile("ldr %1, %0"
> +                     : "+Qo" (*(volatile u32 __force *)addr),
> +                       "=r" (val));
> +        return val;
> +}
> +
> +#define __iormb()               rmb()
> +#define __iowmb()               wmb()
> +
> +#define readb_relaxed(c) ({ u8  __r = __raw_readb(c); __r; })
> +#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
> +                                        __raw_readl(c)); __r; })
> +
> +#define writeb_relaxed(v,c)     __raw_writeb(v,c)
> +#define writel_relaxed(v,c)     __raw_writel((__force u32) cpu_to_le32(v),c)
> +
> +#define readb(c)                ({ u8  __v = readb_relaxed(c); __iormb(); 
> __v; })
> +#define readl(c)                ({ u32 __v = readl_relaxed(c); __iormb(); 
> __v; })
> +
> +#define writeb(v,c)             ({ __iowmb(); writeb_relaxed(v,c); })
> +#define writel(v,c)             ({ __iowmb(); writel_relaxed(v,c); })
> +
> #endif
> /*
>  * Local variables:
> 
> 


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.