[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2] ns16550: add support for polling mode when device tree is used
RISC-V doesn't support interrupts for the time being, so it would be nice to have polling mode. The patch assumes that polling mode will be used if there is no interrupt property or the interrupt is equal to some unused UART interrupt number ( look at the definition of NO_IRQ_POLL in ns16550.c ). Also, the patch updates other places where '0' ( use NO_IRQ_POLL instead of '0' ) was used to set that polling mode should be used. It is possible that interrupt '0' can be used for some architectures as an legal UART interrupt number ( according to dts files in Linux kernel ). For example: https://github.com/torvalds/linux/blob/master/arch/powerpc/boot/dts/ebony.dts#L197 Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx> --- xen/drivers/char/ns16550.c | 51 ++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c index 2aed6ec707..2547f53f5a 100644 --- a/xen/drivers/char/ns16550.c +++ b/xen/drivers/char/ns16550.c @@ -40,6 +40,8 @@ #include <asm/fixmap.h> #endif +#define NO_IRQ_POLL 0 + static struct ns16550 { int baud, clock_hz, data_bits, parity, stop_bits, fifo_size, irq; u64 io_base; /* I/O port or memory-mapped I/O address. */ @@ -58,7 +60,11 @@ static struct ns16550 { struct timer timer; struct timer resume_timer; unsigned int timeout_ms; - bool_t intr_works; + enum { + intr_off, + intr_on, + polling, + } intr_works; bool_t dw_usr_bsy; #ifdef NS16550_PCI /* PCI card parameters. */ @@ -181,7 +187,7 @@ static void cf_check ns16550_interrupt( struct serial_port *port = dev_id; struct ns16550 *uart = port->uart; - uart->intr_works = 1; + uart->intr_works = intr_on; while ( !(ns_read_reg(uart, UART_IIR) & UART_IIR_NOINT) ) { @@ -212,7 +218,7 @@ static void cf_check __ns16550_poll(struct cpu_user_regs *regs) struct serial_port *port = this_cpu(poll_port); struct ns16550 *uart = port->uart; - if ( uart->intr_works ) + if ( uart->intr_works == intr_on ) return; /* Interrupts work - no more polling */ while ( ns_read_reg(uart, UART_LSR) & UART_LSR_DR ) @@ -305,7 +311,8 @@ static void ns16550_setup_preirq(struct ns16550 *uart) unsigned char lcr; unsigned int divisor; - uart->intr_works = 0; + if ( uart->intr_works != polling ) + uart->intr_works = intr_off; pci_serial_early_init(uart); @@ -394,7 +401,7 @@ static void __init cf_check ns16550_init_irq(struct serial_port *port) static void ns16550_setup_postirq(struct ns16550 *uart) { - if ( uart->irq > 0 ) + if ( uart->intr_works != polling ) { /* Master interrupt enable; also keep DTR/RTS asserted. */ ns_write_reg(uart, @@ -472,7 +479,8 @@ static void __init cf_check ns16550_init_postirq(struct serial_port *port) if ( rc ) { - uart->irq = 0; + uart->irq = NO_IRQ_POLL; + uart->intr_works = polling; if ( msi_desc ) msi_free_irq(msi_desc); else @@ -488,7 +496,7 @@ static void __init cf_check ns16550_init_postirq(struct serial_port *port) } #endif - if ( uart->irq > 0 ) + if ( uart->intr_works != polling ) { uart->irqaction.handler = ns16550_interrupt; uart->irqaction.name = "ns16550"; @@ -595,7 +603,9 @@ static void __init cf_check ns16550_endboot(struct serial_port *port) static int __init cf_check ns16550_irq(struct serial_port *port) { struct ns16550 *uart = port->uart; - return ((uart->irq > 0) ? uart->irq : -1); + + return (((uart->intr_works != polling) && (uart->irq >= 0)) ? + uart->irq : -1); } static void cf_check ns16550_start_tx(struct serial_port *port) @@ -1330,9 +1340,12 @@ pci_uart_config(struct ns16550 *uart, bool_t skip_amt, unsigned int idx) * as special only for X86. */ if ( uart->irq == 0xff ) - uart->irq = 0; + { + uart->irq = NO_IRQ_POLL; + uart->intr_works = polling; + } #endif - if ( !uart->irq ) + if ( uart->intr_works == polling ) printk(XENLOG_INFO "ns16550: %pp: no legacy IRQ, using poll mode\n", &PCI_SBDF(0, b, d, f)); @@ -1551,7 +1564,8 @@ static bool __init parse_positional(struct ns16550 *uart, char **str) { conf += 3; uart->msi = true; - uart->irq = 0; + uart->irq = NO_IRQ_POLL; + uart->intr_works = polling; } else #endif @@ -1791,8 +1805,19 @@ static int __init ns16550_uart_dt_init(struct dt_device_node *dev, } res = platform_get_irq(dev, 0); - if ( ! res ) - return -EINVAL; + if ( (res < 0 ) || (res == NO_IRQ_POLL) ) + { + printk("ns1650: polling will be used\n"); + + /* + * If the node doesn't have any interrupt or an interrupt number is + * equal to reserved NO_IRQ_POLL, then it means the driver + * will want to using polling. + */ + res = NO_IRQ_POLL; + + uart->intr_works = polling; + } uart->irq = res; uart->dw_usr_bsy = dt_device_is_compatible(dev, "snps,dw-apb-uart"); -- 2.41.0
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |