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

[xen staging] ns16550: move PCI arrays next to the function using them



commit 510cdda6865868080f898543fc44044020efca71
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Tue Nov 24 11:27:49 2020 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Nov 24 11:27:49 2020 +0100

    ns16550: move PCI arrays next to the function using them
    
    Pure code motion; no functional change intended.
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>
    Reviewed-by: Rahul Singh <rahul.singh@xxxxxxx>
---
 xen/drivers/char/ns16550.c | 1247 ++++++++++++++++++++++----------------------
 1 file changed, 625 insertions(+), 622 deletions(-)

diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index d8b52eb813..6f7fad6093 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -153,418 +153,112 @@ struct ns16550_config_param {
     unsigned int uart_offset;
     unsigned int first_offset;
 };
+#endif
 
-/*
- * Create lookup tables for specific devices. It is assumed that if
- * the device found is MMIO, then you have indexed it here. Else, the
- * driver does nothing for MMIO based devices.
- */
-static const struct ns16550_config_param __initconst uart_param[] = {
-    [param_default] = {
-        .reg_width = 1,
-        .lsr_mask = UART_LSR_THRE,
-        .max_ports = 1,
-    },
-    [param_trumanage] = {
-        .reg_shift = 2,
-        .reg_width = 1,
-        .fifo_size = 16,
-        .lsr_mask = (UART_LSR_THRE | UART_LSR_TEMT),
-        .mmio = 1,
-        .max_ports = 1,
-    },
-    [param_oxford] = {
-        .base_baud = 4000000,
-        .uart_offset = 0x200,
-        .first_offset = 0x1000,
-        .reg_width = 1,
-        .fifo_size = 16,
-        .lsr_mask = UART_LSR_THRE,
-        .mmio = 1,
-        .max_ports = 1, /* It can do more, but we would need more custom 
code.*/
-    },
-    [param_oxford_2port] = {
-        .base_baud = 4000000,
-        .uart_offset = 0x200,
-        .first_offset = 0x1000,
-        .reg_width = 1,
-        .fifo_size = 16,
-        .lsr_mask = UART_LSR_THRE,
-        .mmio = 1,
-        .max_ports = 2,
-    },
-    [param_pericom_1port] = {
-        .base_baud = 921600,
-        .uart_offset = 8,
-        .reg_width = 1,
-        .fifo_size = 16,
-        .lsr_mask = UART_LSR_THRE,
-        .bar0 = 1,
-        .max_ports = 1,
-    },
-    [param_pericom_2port] = {
-        .base_baud = 921600,
-        .uart_offset = 8,
-        .reg_width = 1,
-        .fifo_size = 16,
-        .lsr_mask = UART_LSR_THRE,
-        .bar0 = 1,
-        .max_ports = 2,
-    },
-    /*
-     * Of the two following ones, we can't really use all of their ports,
-     * unless ns16550_com[] would get grown.
-     */
-    [param_pericom_4port] = {
-        .base_baud = 921600,
-        .uart_offset = 8,
-        .reg_width = 1,
-        .fifo_size = 16,
-        .lsr_mask = UART_LSR_THRE,
-        .bar0 = 1,
-        .max_ports = 4,
-    },
-    [param_pericom_8port] = {
-        .base_baud = 921600,
-        .uart_offset = 8,
-        .reg_width = 1,
-        .fifo_size = 16,
-        .lsr_mask = UART_LSR_THRE,
-        .bar0 = 1,
-        .max_ports = 8,
-    }
-};
-static const struct ns16550_config __initconst uart_config[] =
+static void ns16550_delayed_resume(void *data);
+
+static u8 ns_read_reg(struct ns16550 *uart, unsigned int reg)
 {
-    /* Broadcom TruManage device */
-    {
-        .vendor_id = PCI_VENDOR_ID_BROADCOM,
-        .dev_id = 0x160a,
-        .param = param_trumanage,
-    },
-    /* OXPCIe952 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc11b,
-        .param = param_oxford,
-    },
-    /* OXPCIe952 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc11f,
-        .param = param_oxford,
-    },
-    /* OXPCIe952 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc138,
-        .param = param_oxford,
-    },
-    /* OXPCIe952 2 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc158,
-        .param = param_oxford_2port,
-    },
-    /* OXPCIe952 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc13d,
-        .param = param_oxford,
-    },
-    /* OXPCIe952 2 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc15d,
-        .param = param_oxford_2port,
-    },
-    /* OXPCIe952 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc40b,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc40f,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
+    void __iomem *addr = uart->remapped_io_base + (reg << uart->reg_shift);
+#ifdef CONFIG_HAS_IOPORTS
+    if ( uart->remapped_io_base == NULL )
+        return inb(uart->io_base + reg);
+#endif
+    switch ( uart->reg_width )
     {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc41b,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
+    case 1:
+        return readb(addr);
+    case 4:
+        return readl(addr);
+    default:
+        return 0xff;
+    }
+}
+
+static void ns_write_reg(struct ns16550 *uart, unsigned int reg, u8 c)
+{
+    void __iomem *addr = uart->remapped_io_base + (reg << uart->reg_shift);
+#ifdef CONFIG_HAS_IOPORTS
+    if ( uart->remapped_io_base == NULL )
+        return outb(c, uart->io_base + reg);
+#endif
+    switch ( uart->reg_width )
     {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc41f,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
+    case 1:
+        writeb(c, addr);
+        break;
+    case 4:
+        writel(c, addr);
+        break;
+    default:
+        /* Ignored */
+        break;
+    }
+}
+
+static int ns16550_ioport_invalid(struct ns16550 *uart)
+{
+    return ns_read_reg(uart, UART_IER) == 0xff;
+}
+
+static void handle_dw_usr_busy_quirk(struct ns16550 *uart)
+{
+    if ( uart->dw_usr_bsy &&
+         (ns_read_reg(uart, UART_IIR) & UART_IIR_BSY) == UART_IIR_BSY )
     {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc42b,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
+        /* DesignWare 8250 detects if LCR is written while the UART is
+         * busy and raises a "busy detect" interrupt. Read the UART
+         * Status Register to clear this state.
+         *
+         * Allwinner/sunxi UART hardware is similar to DesignWare 8250
+         * and also contains a "busy detect" interrupt. So this quirk
+         * fix will also be used for Allwinner UART.
+         */
+        ns_read_reg(uart, UART_USR);
+    }
+}
+
+static void ns16550_interrupt(
+    int irq, void *dev_id, struct cpu_user_regs *regs)
+{
+    struct serial_port *port = dev_id;
+    struct ns16550 *uart = port->uart;
+
+    uart->intr_works = 1;
+
+    while ( !(ns_read_reg(uart, UART_IIR) & UART_IIR_NOINT) )
     {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc42f,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc43b,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc43f,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc44b,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc44f,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc45b,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc45f,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc46b,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc46f,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc47b,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc47f,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc48b,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc48f,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc49b,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc49f,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc4ab,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc4af,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc4bb,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc4bf,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc4cb,
-        .param = param_oxford,
-    },
-    /* OXPCIe200 1 Native UART  */
-    {
-        .vendor_id = PCI_VENDOR_ID_OXSEMI,
-        .dev_id = 0xc4cf,
-        .param = param_oxford,
-    },
-    /* Pericom PI7C9X7951 Uno UART */
-    {
-        .vendor_id = PCI_VENDOR_ID_PERICOM,
-        .dev_id = 0x7951,
-        .param = param_pericom_1port
-    },
-    /* Pericom PI7C9X7952 Duo UART */
-    {
-        .vendor_id = PCI_VENDOR_ID_PERICOM,
-        .dev_id = 0x7952,
-        .param = param_pericom_2port
-    },
-    /* Pericom PI7C9X7954 Quad UART */
-    {
-        .vendor_id = PCI_VENDOR_ID_PERICOM,
-        .dev_id = 0x7954,
-        .param = param_pericom_4port
-    },
-    /* Pericom PI7C9X7958 Octal UART */
-    {
-        .vendor_id = PCI_VENDOR_ID_PERICOM,
-        .dev_id = 0x7958,
-        .param = param_pericom_8port
-    }
-};
-#endif
-
-static void ns16550_delayed_resume(void *data);
-
-static u8 ns_read_reg(struct ns16550 *uart, unsigned int reg)
-{
-    void __iomem *addr = uart->remapped_io_base + (reg << uart->reg_shift);
-#ifdef CONFIG_HAS_IOPORTS
-    if ( uart->remapped_io_base == NULL )
-        return inb(uart->io_base + reg);
-#endif
-    switch ( uart->reg_width )
-    {
-    case 1:
-        return readb(addr);
-    case 4:
-        return readl(addr);
-    default:
-        return 0xff;
-    }
-}
-
-static void ns_write_reg(struct ns16550 *uart, unsigned int reg, u8 c)
-{
-    void __iomem *addr = uart->remapped_io_base + (reg << uart->reg_shift);
-#ifdef CONFIG_HAS_IOPORTS
-    if ( uart->remapped_io_base == NULL )
-        return outb(c, uart->io_base + reg);
-#endif
-    switch ( uart->reg_width )
-    {
-    case 1:
-        writeb(c, addr);
-        break;
-    case 4:
-        writel(c, addr);
-        break;
-    default:
-        /* Ignored */
-        break;
-    }
-}
-
-static int ns16550_ioport_invalid(struct ns16550 *uart)
-{
-    return ns_read_reg(uart, UART_IER) == 0xff;
-}
-
-static void handle_dw_usr_busy_quirk(struct ns16550 *uart)
-{
-    if ( uart->dw_usr_bsy &&
-         (ns_read_reg(uart, UART_IIR) & UART_IIR_BSY) == UART_IIR_BSY )
-    {
-        /* DesignWare 8250 detects if LCR is written while the UART is
-         * busy and raises a "busy detect" interrupt. Read the UART
-         * Status Register to clear this state.
-         *
-         * Allwinner/sunxi UART hardware is similar to DesignWare 8250
-         * and also contains a "busy detect" interrupt. So this quirk
-         * fix will also be used for Allwinner UART.
-         */
-        ns_read_reg(uart, UART_USR);
-    }
-}
-
-static void ns16550_interrupt(
-    int irq, void *dev_id, struct cpu_user_regs *regs)
-{
-    struct serial_port *port = dev_id;
-    struct ns16550 *uart = port->uart;
-
-    uart->intr_works = 1;
-
-    while ( !(ns_read_reg(uart, UART_IIR) & UART_IIR_NOINT) )
-    {
-        u8 lsr = ns_read_reg(uart, UART_LSR);
-
-        if ( (lsr & uart->lsr_mask) == uart->lsr_mask )
-            serial_tx_interrupt(port, regs);
-        if ( lsr & UART_LSR_DR )
-            serial_rx_interrupt(port, regs);
-
-        /* A "busy-detect" condition is observed on Allwinner/sunxi UART
-         * after LCR is written during setup. It needs to be cleared at
-         * this point or UART_IIR_NOINT will never be set and this loop
-         * will continue forever.
-         *
-         * This state can be cleared by calling the dw_usr_busy quirk
-         * handler that resolves "busy-detect" for  DesignWare uart.
-         */
-        handle_dw_usr_busy_quirk(uart);
-    }
-}
-
-/* Safe: ns16550_poll() runs as softirq so not reentrant on a given CPU. */
-static DEFINE_PER_CPU(struct serial_port *, poll_port);
-
-static void __ns16550_poll(struct cpu_user_regs *regs)
-{
-    struct serial_port *port = this_cpu(poll_port);
-    struct ns16550 *uart = port->uart;
-
-    if ( uart->intr_works )
-        return; /* Interrupts work - no more polling */
-
-    while ( ns_read_reg(uart, UART_LSR) & UART_LSR_DR )
+        u8 lsr = ns_read_reg(uart, UART_LSR);
+
+        if ( (lsr & uart->lsr_mask) == uart->lsr_mask )
+            serial_tx_interrupt(port, regs);
+        if ( lsr & UART_LSR_DR )
+            serial_rx_interrupt(port, regs);
+
+        /* A "busy-detect" condition is observed on Allwinner/sunxi UART
+         * after LCR is written during setup. It needs to be cleared at
+         * this point or UART_IIR_NOINT will never be set and this loop
+         * will continue forever.
+         *
+         * This state can be cleared by calling the dw_usr_busy quirk
+         * handler that resolves "busy-detect" for  DesignWare uart.
+         */
+        handle_dw_usr_busy_quirk(uart);
+    }
+}
+
+/* Safe: ns16550_poll() runs as softirq so not reentrant on a given CPU. */
+static DEFINE_PER_CPU(struct serial_port *, poll_port);
+
+static void __ns16550_poll(struct cpu_user_regs *regs)
+{
+    struct serial_port *port = this_cpu(poll_port);
+    struct ns16550 *uart = port->uart;
+
+    if ( uart->intr_works )
+        return; /* Interrupts work - no more polling */
+
+    while ( ns_read_reg(uart, UART_LSR) & UART_LSR_DR )
     {
         if ( ns16550_ioport_invalid(uart) )
             goto out;
@@ -825,226 +519,534 @@ static void __init ns16550_init_postirq(struct 
serial_port *port)
 
     if ( uart->irq > 0 )
     {
-        uart->irqaction.handler = ns16550_interrupt;
-        uart->irqaction.name    = "ns16550";
-        uart->irqaction.dev_id  = port;
-        if ( (rc = setup_irq(uart->irq, 0, &uart->irqaction)) != 0 )
-            printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);
-    }
-
-    ns16550_setup_postirq(uart);
-}
-
-static void ns16550_suspend(struct serial_port *port)
-{
-    struct ns16550 *uart = port->uart;
-
-    stop_timer(&uart->timer);
-
-#ifdef CONFIG_HAS_PCI
-    if ( uart->bar )
-       uart->cr = pci_conf_read16(PCI_SBDF(0, uart->ps_bdf[0], uart->ps_bdf[1],
-                                  uart->ps_bdf[2]), PCI_COMMAND);
-#endif
-}
-
-static void _ns16550_resume(struct serial_port *port)
-{
-#ifdef CONFIG_HAS_PCI
-    struct ns16550 *uart = port->uart;
-
-    if ( uart->bar )
+        uart->irqaction.handler = ns16550_interrupt;
+        uart->irqaction.name    = "ns16550";
+        uart->irqaction.dev_id  = port;
+        if ( (rc = setup_irq(uart->irq, 0, &uart->irqaction)) != 0 )
+            printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);
+    }
+
+    ns16550_setup_postirq(uart);
+}
+
+static void ns16550_suspend(struct serial_port *port)
+{
+    struct ns16550 *uart = port->uart;
+
+    stop_timer(&uart->timer);
+
+#ifdef CONFIG_HAS_PCI
+    if ( uart->bar )
+       uart->cr = pci_conf_read16(PCI_SBDF(0, uart->ps_bdf[0], uart->ps_bdf[1],
+                                  uart->ps_bdf[2]), PCI_COMMAND);
+#endif
+}
+
+static void _ns16550_resume(struct serial_port *port)
+{
+#ifdef CONFIG_HAS_PCI
+    struct ns16550 *uart = port->uart;
+
+    if ( uart->bar )
+    {
+       pci_conf_write32(PCI_SBDF(0, uart->ps_bdf[0], uart->ps_bdf[1],
+                                 uart->ps_bdf[2]),
+                        PCI_BASE_ADDRESS_0 + uart->bar_idx*4, uart->bar);
+
+        /* If 64 bit BAR, write higher 32 bits to BAR+4 */
+        if ( uart->bar & PCI_BASE_ADDRESS_MEM_TYPE_64 )
+            pci_conf_write32(PCI_SBDF(0, uart->ps_bdf[0],  uart->ps_bdf[1],
+                                      uart->ps_bdf[2]),
+                        PCI_BASE_ADDRESS_0 + (uart->bar_idx+1)*4, uart->bar64);
+
+       pci_conf_write16(PCI_SBDF(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);
+}
+
+static int delayed_resume_tries;
+static void ns16550_delayed_resume(void *data)
+{
+    struct serial_port *port = data;
+    struct ns16550 *uart = port->uart;
+
+    if ( ns16550_ioport_invalid(port->uart) && delayed_resume_tries-- )
+        set_timer(&uart->resume_timer, NOW() + RESUME_DELAY);
+    else
+        _ns16550_resume(port);
+}
+
+static void ns16550_resume(struct serial_port *port)
+{
+    struct ns16550 *uart = port->uart;
+
+    /*
+     * Check for ioport access, before fully resuming operation.
+     * On some systems, there is a SuperIO card that provides
+     * this legacy ioport on the LPC bus.
+     *
+     * We need to wait for dom0's ACPI processing to run the proper
+     * AML to re-initialize the chip, before we can use the card again.
+     *
+     * This may cause a small amount of garbage to be written
+     * to the serial log while we wait patiently for that AML to
+     * be executed. However, this is preferable to spinning in an
+     * infinite loop, as seen on a Lenovo T430, when serial was enabled.
+     */
+    if ( ns16550_ioport_invalid(uart) )
+    {
+        delayed_resume_tries = RESUME_RETRIES;
+        set_timer(&uart->resume_timer, NOW() + RESUME_DELAY);
+    }
+    else
+        _ns16550_resume(port);
+}
+
+static void __init ns16550_endboot(struct serial_port *port)
+{
+#ifdef CONFIG_HAS_IOPORTS
+    struct ns16550 *uart = port->uart;
+    int rv;
+
+    if ( uart->remapped_io_base )
+        return;
+    rv = ioports_deny_access(hardware_domain, uart->io_base, uart->io_base + 
7);
+    if ( rv != 0 )
+        BUG();
+#endif
+}
+
+static int __init ns16550_irq(struct serial_port *port)
+{
+    struct ns16550 *uart = port->uart;
+    return ((uart->irq > 0) ? uart->irq : -1);
+}
+
+static void ns16550_start_tx(struct serial_port *port)
+{
+    struct ns16550 *uart = port->uart;
+    u8 ier = ns_read_reg(uart, UART_IER);
+
+    /* Unmask transmit holding register empty interrupt if currently masked. */
+    if ( !(ier & UART_IER_ETHREI) )
+        ns_write_reg(uart, UART_IER, ier | UART_IER_ETHREI);
+}
+
+static void ns16550_stop_tx(struct serial_port *port)
+{
+    struct ns16550 *uart = port->uart;
+    u8 ier = ns_read_reg(uart, UART_IER);
+
+    /* Mask off transmit holding register empty interrupt if currently 
unmasked. */
+    if ( ier & UART_IER_ETHREI )
+        ns_write_reg(uart, UART_IER, ier & ~UART_IER_ETHREI);
+}
+
+#ifdef CONFIG_ARM
+static const struct vuart_info *ns16550_vuart_info(struct serial_port *port)
+{
+    struct ns16550 *uart = port->uart;
+
+    return &uart->vuart;
+}
+#endif
+
+static struct uart_driver __read_mostly ns16550_driver = {
+    .init_preirq  = ns16550_init_preirq,
+    .init_irq     = ns16550_init_irq,
+    .init_postirq = ns16550_init_postirq,
+    .endboot      = ns16550_endboot,
+    .suspend      = ns16550_suspend,
+    .resume       = ns16550_resume,
+    .tx_ready     = ns16550_tx_ready,
+    .putc         = ns16550_putc,
+    .getc         = ns16550_getc,
+    .irq          = ns16550_irq,
+    .start_tx     = ns16550_start_tx,
+    .stop_tx      = ns16550_stop_tx,
+#ifdef CONFIG_ARM
+    .vuart_info   = ns16550_vuart_info,
+#endif
+};
+
+static int __init parse_parity_char(int c)
+{
+    switch ( c )
+    {
+    case 'n':
+        return UART_PARITY_NONE;
+    case 'o': 
+        return UART_PARITY_ODD;
+    case 'e': 
+        return UART_PARITY_EVEN;
+    case 'm': 
+        return UART_PARITY_MARK;
+    case 's': 
+        return UART_PARITY_SPACE;
+    }
+    return 0;
+}
+
+static int __init check_existence(struct ns16550 *uart)
+{
+    unsigned char status, scratch, scratch2, scratch3;
+
+#ifdef CONFIG_HAS_IOPORTS
+    /*
+     * We can't poke MMIO UARTs until they get I/O remapped later. Assume that
+     * if we're getting MMIO UARTs, the arch code knows what it's doing.
+     */
+    if ( uart->io_base >= 0x10000 )
+        return 1;
+#else
+    return 1; /* Everything is MMIO */
+#endif
+
+#ifdef CONFIG_HAS_PCI
+    pci_serial_early_init(uart);
+#endif
+
+    /*
+     * Do a simple existence test first; if we fail this,
+     * there's no point trying anything else.
+     */
+    scratch = ns_read_reg(uart, UART_IER);
+    ns_write_reg(uart, UART_IER, 0);
+
+    /*
+     * Mask out IER[7:4] bits for test as some UARTs (e.g. TL
+     * 16C754B) allow only to modify them if an EFR bit is set.
+     */
+    scratch2 = ns_read_reg(uart, UART_IER) & 0x0f;
+    ns_write_reg(uart,UART_IER, 0x0F);
+    scratch3 = ns_read_reg(uart, UART_IER) & 0x0f;
+    ns_write_reg(uart, UART_IER, scratch);
+    if ( (scratch2 != 0) || (scratch3 != 0x0F) )
+        return 0;
+
+    /*
+     * Check to see if a UART is really there.
+     * Use loopback test mode.
+     */
+    ns_write_reg(uart, UART_MCR, UART_MCR_LOOP | 0x0A);
+    status = ns_read_reg(uart, UART_MSR) & 0xF0;
+    return (status == 0x90);
+}
+
+#ifdef CONFIG_HAS_PCI
+
+/*
+ * Create lookup tables for specific devices. It is assumed that if
+ * the device found is MMIO, then you have indexed it here. Else, the
+ * driver does nothing for MMIO based devices.
+ */
+static const struct ns16550_config_param __initconst uart_param[] = {
+    [param_default] = {
+        .reg_width = 1,
+        .lsr_mask = UART_LSR_THRE,
+        .max_ports = 1,
+    },
+    [param_trumanage] = {
+        .reg_shift = 2,
+        .reg_width = 1,
+        .fifo_size = 16,
+        .lsr_mask = (UART_LSR_THRE | UART_LSR_TEMT),
+        .mmio = 1,
+        .max_ports = 1,
+    },
+    [param_oxford] = {
+        .base_baud = 4000000,
+        .uart_offset = 0x200,
+        .first_offset = 0x1000,
+        .reg_width = 1,
+        .fifo_size = 16,
+        .lsr_mask = UART_LSR_THRE,
+        .mmio = 1,
+        .max_ports = 1, /* It can do more, but we would need more custom 
code.*/
+    },
+    [param_oxford_2port] = {
+        .base_baud = 4000000,
+        .uart_offset = 0x200,
+        .first_offset = 0x1000,
+        .reg_width = 1,
+        .fifo_size = 16,
+        .lsr_mask = UART_LSR_THRE,
+        .mmio = 1,
+        .max_ports = 2,
+    },
+    [param_pericom_1port] = {
+        .base_baud = 921600,
+        .uart_offset = 8,
+        .reg_width = 1,
+        .fifo_size = 16,
+        .lsr_mask = UART_LSR_THRE,
+        .bar0 = 1,
+        .max_ports = 1,
+    },
+    [param_pericom_2port] = {
+        .base_baud = 921600,
+        .uart_offset = 8,
+        .reg_width = 1,
+        .fifo_size = 16,
+        .lsr_mask = UART_LSR_THRE,
+        .bar0 = 1,
+        .max_ports = 2,
+    },
+    /*
+     * Of the two following ones, we can't really use all of their ports,
+     * unless ns16550_com[] would get grown.
+     */
+    [param_pericom_4port] = {
+        .base_baud = 921600,
+        .uart_offset = 8,
+        .reg_width = 1,
+        .fifo_size = 16,
+        .lsr_mask = UART_LSR_THRE,
+        .bar0 = 1,
+        .max_ports = 4,
+    },
+    [param_pericom_8port] = {
+        .base_baud = 921600,
+        .uart_offset = 8,
+        .reg_width = 1,
+        .fifo_size = 16,
+        .lsr_mask = UART_LSR_THRE,
+        .bar0 = 1,
+        .max_ports = 8,
+    }
+};
+
+static const struct ns16550_config __initconst uart_config[] =
+{
+    /* Broadcom TruManage device */
+    {
+        .vendor_id = PCI_VENDOR_ID_BROADCOM,
+        .dev_id = 0x160a,
+        .param = param_trumanage,
+    },
+    /* OXPCIe952 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc11b,
+        .param = param_oxford,
+    },
+    /* OXPCIe952 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc11f,
+        .param = param_oxford,
+    },
+    /* OXPCIe952 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc138,
+        .param = param_oxford,
+    },
+    /* OXPCIe952 2 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc158,
+        .param = param_oxford_2port,
+    },
+    /* OXPCIe952 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc13d,
+        .param = param_oxford,
+    },
+    /* OXPCIe952 2 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc15d,
+        .param = param_oxford_2port,
+    },
+    /* OXPCIe952 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc40b,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc40f,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc41b,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc41f,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc42b,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc42f,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc43b,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc43f,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc44b,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc44f,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc45b,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc45f,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc46b,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc46f,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc47b,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc47f,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc48b,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc48f,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc49b,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc49f,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc4ab,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc4af,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc4bb,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
+    {
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc4bf,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
     {
-       pci_conf_write32(PCI_SBDF(0, uart->ps_bdf[0], uart->ps_bdf[1],
-                                 uart->ps_bdf[2]),
-                        PCI_BASE_ADDRESS_0 + uart->bar_idx*4, uart->bar);
-
-        /* If 64 bit BAR, write higher 32 bits to BAR+4 */
-        if ( uart->bar & PCI_BASE_ADDRESS_MEM_TYPE_64 )
-            pci_conf_write32(PCI_SBDF(0, uart->ps_bdf[0],  uart->ps_bdf[1],
-                                      uart->ps_bdf[2]),
-                        PCI_BASE_ADDRESS_0 + (uart->bar_idx+1)*4, uart->bar64);
-
-       pci_conf_write16(PCI_SBDF(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);
-}
-
-static int delayed_resume_tries;
-static void ns16550_delayed_resume(void *data)
-{
-    struct serial_port *port = data;
-    struct ns16550 *uart = port->uart;
-
-    if ( ns16550_ioport_invalid(port->uart) && delayed_resume_tries-- )
-        set_timer(&uart->resume_timer, NOW() + RESUME_DELAY);
-    else
-        _ns16550_resume(port);
-}
-
-static void ns16550_resume(struct serial_port *port)
-{
-    struct ns16550 *uart = port->uart;
-
-    /*
-     * Check for ioport access, before fully resuming operation.
-     * On some systems, there is a SuperIO card that provides
-     * this legacy ioport on the LPC bus.
-     *
-     * We need to wait for dom0's ACPI processing to run the proper
-     * AML to re-initialize the chip, before we can use the card again.
-     *
-     * This may cause a small amount of garbage to be written
-     * to the serial log while we wait patiently for that AML to
-     * be executed. However, this is preferable to spinning in an
-     * infinite loop, as seen on a Lenovo T430, when serial was enabled.
-     */
-    if ( ns16550_ioport_invalid(uart) )
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc4cb,
+        .param = param_oxford,
+    },
+    /* OXPCIe200 1 Native UART  */
     {
-        delayed_resume_tries = RESUME_RETRIES;
-        set_timer(&uart->resume_timer, NOW() + RESUME_DELAY);
-    }
-    else
-        _ns16550_resume(port);
-}
-
-static void __init ns16550_endboot(struct serial_port *port)
-{
-#ifdef CONFIG_HAS_IOPORTS
-    struct ns16550 *uart = port->uart;
-    int rv;
-
-    if ( uart->remapped_io_base )
-        return;
-    rv = ioports_deny_access(hardware_domain, uart->io_base, uart->io_base + 
7);
-    if ( rv != 0 )
-        BUG();
-#endif
-}
-
-static int __init ns16550_irq(struct serial_port *port)
-{
-    struct ns16550 *uart = port->uart;
-    return ((uart->irq > 0) ? uart->irq : -1);
-}
-
-static void ns16550_start_tx(struct serial_port *port)
-{
-    struct ns16550 *uart = port->uart;
-    u8 ier = ns_read_reg(uart, UART_IER);
-
-    /* Unmask transmit holding register empty interrupt if currently masked. */
-    if ( !(ier & UART_IER_ETHREI) )
-        ns_write_reg(uart, UART_IER, ier | UART_IER_ETHREI);
-}
-
-static void ns16550_stop_tx(struct serial_port *port)
-{
-    struct ns16550 *uart = port->uart;
-    u8 ier = ns_read_reg(uart, UART_IER);
-
-    /* Mask off transmit holding register empty interrupt if currently 
unmasked. */
-    if ( ier & UART_IER_ETHREI )
-        ns_write_reg(uart, UART_IER, ier & ~UART_IER_ETHREI);
-}
-
-#ifdef CONFIG_ARM
-static const struct vuart_info *ns16550_vuart_info(struct serial_port *port)
-{
-    struct ns16550 *uart = port->uart;
-
-    return &uart->vuart;
-}
-#endif
-
-static struct uart_driver __read_mostly ns16550_driver = {
-    .init_preirq  = ns16550_init_preirq,
-    .init_irq     = ns16550_init_irq,
-    .init_postirq = ns16550_init_postirq,
-    .endboot      = ns16550_endboot,
-    .suspend      = ns16550_suspend,
-    .resume       = ns16550_resume,
-    .tx_ready     = ns16550_tx_ready,
-    .putc         = ns16550_putc,
-    .getc         = ns16550_getc,
-    .irq          = ns16550_irq,
-    .start_tx     = ns16550_start_tx,
-    .stop_tx      = ns16550_stop_tx,
-#ifdef CONFIG_ARM
-    .vuart_info   = ns16550_vuart_info,
-#endif
-};
-
-static int __init parse_parity_char(int c)
-{
-    switch ( c )
+        .vendor_id = PCI_VENDOR_ID_OXSEMI,
+        .dev_id = 0xc4cf,
+        .param = param_oxford,
+    },
+    /* Pericom PI7C9X7951 Uno UART */
     {
-    case 'n':
-        return UART_PARITY_NONE;
-    case 'o': 
-        return UART_PARITY_ODD;
-    case 'e': 
-        return UART_PARITY_EVEN;
-    case 'm': 
-        return UART_PARITY_MARK;
-    case 's': 
-        return UART_PARITY_SPACE;
+        .vendor_id = PCI_VENDOR_ID_PERICOM,
+        .dev_id = 0x7951,
+        .param = param_pericom_1port
+    },
+    /* Pericom PI7C9X7952 Duo UART */
+    {
+        .vendor_id = PCI_VENDOR_ID_PERICOM,
+        .dev_id = 0x7952,
+        .param = param_pericom_2port
+    },
+    /* Pericom PI7C9X7954 Quad UART */
+    {
+        .vendor_id = PCI_VENDOR_ID_PERICOM,
+        .dev_id = 0x7954,
+        .param = param_pericom_4port
+    },
+    /* Pericom PI7C9X7958 Octal UART */
+    {
+        .vendor_id = PCI_VENDOR_ID_PERICOM,
+        .dev_id = 0x7958,
+        .param = param_pericom_8port
     }
-    return 0;
-}
-
-static int __init check_existence(struct ns16550 *uart)
-{
-    unsigned char status, scratch, scratch2, scratch3;
-
-#ifdef CONFIG_HAS_IOPORTS
-    /*
-     * We can't poke MMIO UARTs until they get I/O remapped later. Assume that
-     * if we're getting MMIO UARTs, the arch code knows what it's doing.
-     */
-    if ( uart->io_base >= 0x10000 )
-        return 1;
-#else
-    return 1; /* Everything is MMIO */
-#endif
-
-#ifdef CONFIG_HAS_PCI
-    pci_serial_early_init(uart);
-#endif
-
-    /*
-     * Do a simple existence test first; if we fail this,
-     * there's no point trying anything else.
-     */
-    scratch = ns_read_reg(uart, UART_IER);
-    ns_write_reg(uart, UART_IER, 0);
-
-    /*
-     * Mask out IER[7:4] bits for test as some UARTs (e.g. TL
-     * 16C754B) allow only to modify them if an EFR bit is set.
-     */
-    scratch2 = ns_read_reg(uart, UART_IER) & 0x0f;
-    ns_write_reg(uart,UART_IER, 0x0F);
-    scratch3 = ns_read_reg(uart, UART_IER) & 0x0f;
-    ns_write_reg(uart, UART_IER, scratch);
-    if ( (scratch2 != 0) || (scratch3 != 0x0F) )
-        return 0;
-
-    /*
-     * Check to see if a UART is really there.
-     * Use loopback test mode.
-     */
-    ns_write_reg(uart, UART_MCR, UART_MCR_LOOP | 0x0A);
-    status = ns_read_reg(uart, UART_MSR) & 0xF0;
-    return (status == 0x90);
-}
+};
 
-#ifdef CONFIG_HAS_PCI
 static int __init
 pci_uart_config(struct ns16550 *uart, bool_t skip_amt, unsigned int idx)
 {
@@ -1211,7 +1213,8 @@ pci_uart_config(struct ns16550 *uart, bool_t skip_amt, 
unsigned int idx)
 
     return 0;
 }
-#endif
+
+#endif /* CONFIG_HAS_PCI */
 
 /*
  * Used to parse name value pairs and return which value it is along with
--
generated by git-patchbot for /home/xen/git/xen.git#staging



 


Rackspace

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