[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




 


Rackspace

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