* [PATCH V3] ns16550: Add support for UART present in Broadcom TruManage capable NetXtreme chips
@ 2013-11-20 0:54 Aravind Gopalakrishnan
2013-11-20 9:00 ` Jan Beulich
0 siblings, 1 reply; 2+ messages in thread
From: Aravind Gopalakrishnan @ 2013-11-20 0:54 UTC (permalink / raw)
To: xen-devel, jbeulich
Cc: Aravind Gopalakrishnan, Thomas Lendacky, shurd,
Suravee Suthikulpanit, sherry.hurwitz
There are few quirks regarding the chip:
Firstly, it is an MMIO device. Therefore, the code has been modified to
accept MMIO based devices as well. Settings particular to such devices are
populated in the table 'uart_config'. Currently, we only support BCM5725
TruManage chip.
Some more quirks are - the need to shift the register offset by a specific
value and we also need to verify (UART_LSR_THRE && UART_LSR_TEMT) bits before
transmitting data.
While testing, we ned to include com1=115200,8n1,pci,0 on the xen cmdline to
be able to observe output using SOL.
Changes from V2:
- per Jan's comments:
- Use __initdata for uart_config structure
- Add length check for mmio case too
- use unsigned int for new fields in uart_config struct. Bogus int usage
will be corrected in a follow-up patch.
- Misc:
- assign uart->io_size to length after calculation
(if arch != x86, then ioremap uses uart->io_size)
- use fifo_size = 16, as I noticed some characters dropped when
fifo_size = 64.
Signed-off-by: Aravind Gopalakrishnan <Aravind.Gopalakrishnan@amd.com>
Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Signed-off-by: Thomas Lendacky <Thomas.Lendacky@amd.com>
---
xen/drivers/char/ns16550.c | 109 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 96 insertions(+), 13 deletions(-)
diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index 9c2cded..b199d79 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -53,6 +53,7 @@ static struct ns16550 {
char __iomem *remapped_io_base; /* Remapped virtual address of MMIO. */
/* UART with IRQ line: interrupt-driven I/O. */
struct irqaction irqaction;
+ u8 lsr_mask;
#ifdef CONFIG_ARM
struct vuart_info vuart;
#endif
@@ -77,6 +78,37 @@ static struct ns16550 {
#endif
} ns16550_com[2] = { { 0 } };
+/* Defining uart config options for MMIO devices */
+struct ns16550_config_mmio {
+ u16 vendor_id;
+ u16 dev_id;
+ int reg_shift;
+ int reg_width;
+ int fifo_size;
+ u8 lsr_mask;
+ unsigned int max_bars;
+};
+
+/*
+ * Create lookup tables for specific MMIO devices..
+ * It is assumed that if the device found is MMIO,
+ * then you have indexed it here. Else, the driver
+ * does nothing.
+ */
+static struct ns16550_config_mmio __initdata uart_config[] =
+{
+ /* Broadcom TruManage device */
+ {
+ .vendor_id = 0x14e4,
+ .dev_id = 0x160a,
+ .reg_shift = 2,
+ .reg_width = 1,
+ .fifo_size = 16,
+ .lsr_mask = (UART_LSR_THRE | UART_LSR_TEMT),
+ .max_bars = 1,
+ },
+};
+
static void ns16550_delayed_resume(void *data);
static char ns_read_reg(struct ns16550 *uart, int reg)
@@ -134,7 +166,7 @@ static void ns16550_interrupt(
while ( !(ns_read_reg(uart, UART_IIR) & UART_IIR_NOINT) )
{
char lsr = ns_read_reg(uart, UART_LSR);
- if ( lsr & UART_LSR_THRE )
+ if ( (lsr & uart->lsr_mask) == uart->lsr_mask )
serial_tx_interrupt(port, regs);
if ( lsr & UART_LSR_DR )
serial_rx_interrupt(port, regs);
@@ -160,7 +192,7 @@ static void __ns16550_poll(struct cpu_user_regs *regs)
serial_rx_interrupt(port, regs);
}
- if ( ns_read_reg(uart, UART_LSR) & UART_LSR_THRE )
+ if ( ( ns_read_reg(uart, UART_LSR) & uart->lsr_mask ) == uart->lsr_mask )
serial_tx_interrupt(port, regs);
out:
@@ -183,7 +215,9 @@ static int ns16550_tx_ready(struct serial_port *port)
if ( ns16550_ioport_invalid(uart) )
return -EIO;
- return ns_read_reg(uart, UART_LSR) & UART_LSR_THRE ? uart->fifo_size : 0;
+
+ return ( (ns_read_reg(uart, UART_LSR) &
+ uart->lsr_mask ) == uart->lsr_mask ) ? uart->fifo_size : 0;
}
static void ns16550_putc(struct serial_port *port, char c)
@@ -546,11 +580,12 @@ static int __init check_existence(struct ns16550 *uart)
}
#ifdef HAS_PCI
-static int
+static int __init
pci_uart_config (struct ns16550 *uart, int skip_amt, int bar_idx)
{
uint32_t bar, len;
- int b, d, f, nextf;
+ int b, d, f, nextf, i;
+ u16 vendor, device;
/* NB. Start at bus 1 to avoid AMT: a plug-in card cannot be on bus 0. */
for ( b = skip_amt ? 1 : 0; b < 0x100; b++ )
@@ -581,22 +616,67 @@ pci_uart_config (struct ns16550 *uart, int skip_amt, int bar_idx)
/* Not IO */
if ( !(bar & PCI_BASE_ADDRESS_SPACE_IO) )
- continue;
+ {
+ vendor = pci_conf_read16(0, b, d, f, PCI_VENDOR_ID);
+ device = pci_conf_read16(0, b, d, f, PCI_DEVICE_ID);
+
+ /* Check for quirks in uart_config lookup table */
+ for ( i = 0; i < ARRAY_SIZE(uart_config); i++)
+ {
+ if ( uart_config[i].vendor_id != vendor )
+ continue;
+
+ if ( uart_config[i].dev_id != device )
+ continue;
+
+ pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0, ~0u);
+ len = pci_conf_read32(0, b, d, f, PCI_BASE_ADDRESS_0);
+ pci_conf_write32(0, b, d, f,
+ PCI_BASE_ADDRESS_0 + bar_idx*4, bar);
+ len &= ~(0xf);
+ uart->io_size = len & ~(len - 1);
+
+ /* Force length of mmio region to be atleast 8 bytes */
+ if ( uart->io_size < 0x8 )
+ continue;
+
+ if ( bar_idx >= uart_config[i].max_bars )
+ continue;
+
+ if (uart_config[i].fifo_size )
+ uart->fifo_size = uart_config[i].fifo_size;
+
+ uart->reg_shift = uart_config[i].reg_shift;
+ uart->reg_width = uart_config[i].reg_width;
+ uart->lsr_mask = uart_config[i].lsr_mask;
+ uart->io_base = bar & PCI_BASE_ADDRESS_MEM_MASK;
+ break;
+ }
+
+ /* If we have an io_base, then we succeeded in the lookup */
+ if ( !uart->io_base )
+ continue;
+ }
+ /* IO based */
+ else
+ {
+ pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0, ~0u);
+ len = pci_conf_read32(0, b, d, f, PCI_BASE_ADDRESS_0);
+ pci_conf_write32(0, b, d, f,
+ PCI_BASE_ADDRESS_0 + bar_idx*4, bar);
- pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0, ~0u);
- len = pci_conf_read32(0, b, d, f, PCI_BASE_ADDRESS_0);
- pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4, bar);
+ /* Not 8 bytes */
+ if ( (len & 0xffff) != 0xfff9 )
+ continue;
- /* Not 8 bytes */
- if ( (len & 0xffff) != 0xfff9 )
- continue;
+ uart->io_base = bar & ~PCI_BASE_ADDRESS_SPACE_IO;
+ }
uart->ps_bdf[0] = b;
uart->ps_bdf[1] = d;
uart->ps_bdf[2] = f;
uart->bar = bar;
uart->bar_idx = bar_idx;
- uart->io_base = bar & ~PCI_BASE_ADDRESS_SPACE_IO;
uart->irq = pci_conf_read8(0, b, d, f, PCI_INTERRUPT_PIN) ?
pci_conf_read8(0, b, d, f, PCI_INTERRUPT_LINE) : 0;
@@ -746,6 +826,9 @@ void __init ns16550_init(int index, struct ns16550_defaults *defaults)
/* Default is no transmit FIFO. */
uart->fifo_size = 1;
+ /* Default lsr_mask = UART_LSR_THRE */
+ uart->lsr_mask = UART_LSR_THRE;
+
ns16550_parse_port_config(uart, (index == 0) ? opt_com1 : opt_com2);
}
--
1.8.1.2
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH V3] ns16550: Add support for UART present in Broadcom TruManage capable NetXtreme chips
2013-11-20 0:54 [PATCH V3] ns16550: Add support for UART present in Broadcom TruManage capable NetXtreme chips Aravind Gopalakrishnan
@ 2013-11-20 9:00 ` Jan Beulich
0 siblings, 0 replies; 2+ messages in thread
From: Jan Beulich @ 2013-11-20 9:00 UTC (permalink / raw)
To: Aravind Gopalakrishnan
Cc: Thomas Lendacky, shurd, xen-devel, Suravee Suthikulpanit,
sherry.hurwitz
>>> On 20.11.13 at 01:54, Aravind Gopalakrishnan <Aravind.Gopalakrishnan@amd.com> wrote:
> @@ -77,6 +78,37 @@ static struct ns16550 {
> #endif
> } ns16550_com[2] = { { 0 } };
>
> +/* Defining uart config options for MMIO devices */
> +struct ns16550_config_mmio {
> + u16 vendor_id;
> + u16 dev_id;
> + int reg_shift;
> + int reg_width;
> + int fifo_size;
As Andrew had pointed out before, and as I think I explained before
too - even if you don't adjust existing code in this patch, you
shouldn't introduce further bogus signed integers here.
> @@ -546,11 +580,12 @@ static int __init check_existence(struct ns16550 *uart)
> }
>
> #ifdef HAS_PCI
> -static int
> +static int __init
> pci_uart_config (struct ns16550 *uart, int skip_amt, int bar_idx)
> {
> uint32_t bar, len;
> - int b, d, f, nextf;
> + int b, d, f, nextf, i;
This "i" is another case of a variable clearly wanting to be unsigned.
If making all the other four variables unsigned is okay (which I think
it is), then just do it all in one go. Otherwise you'd have to add a
new line rather than adding to the existing declaration.
> @@ -581,22 +616,67 @@ pci_uart_config (struct ns16550 *uart, int skip_amt, int bar_idx)
>
> /* Not IO */
> if ( !(bar & PCI_BASE_ADDRESS_SPACE_IO) )
> - continue;
> + {
> + vendor = pci_conf_read16(0, b, d, f, PCI_VENDOR_ID);
> + device = pci_conf_read16(0, b, d, f, PCI_DEVICE_ID);
> +
> + /* Check for quirks in uart_config lookup table */
> + for ( i = 0; i < ARRAY_SIZE(uart_config); i++)
> + {
> + if ( uart_config[i].vendor_id != vendor )
> + continue;
> +
> + if ( uart_config[i].dev_id != device )
> + continue;
> +
> + pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0, ~0u);
> + len = pci_conf_read32(0, b, d, f, PCI_BASE_ADDRESS_0);
> + pci_conf_write32(0, b, d, f,
> + PCI_BASE_ADDRESS_0 + bar_idx*4, bar);
> + len &= ~(0xf);
I'm sure there a manifest constant for this.
> + uart->io_size = len & ~(len - 1);
Why not just "-len"?
Also you're not taking 64-bit BARs into consideration here. Minimally
you need to bail upon encountering one.
> +
> + /* Force length of mmio region to be atleast 8 bytes */
"at least"
> + if ( uart->io_size < 0x8 )
> + continue;
> +
> + if ( bar_idx >= uart_config[i].max_bars )
> + continue;
I suppose this would better be moved up.
> +
> + if (uart_config[i].fifo_size )
Coding style.
> + uart->fifo_size = uart_config[i].fifo_size;
> +
> + uart->reg_shift = uart_config[i].reg_shift;
> + uart->reg_width = uart_config[i].reg_width;
> + uart->lsr_mask = uart_config[i].lsr_mask;
> + uart->io_base = bar & PCI_BASE_ADDRESS_MEM_MASK;
> + break;
> + }
> +
> + /* If we have an io_base, then we succeeded in the lookup */
> + if ( !uart->io_base )
> + continue;
> + }
> + /* IO based */
> + else
> + {
> + pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0, ~0u);
> + len = pci_conf_read32(0, b, d, f, PCI_BASE_ADDRESS_0);
> + pci_conf_write32(0, b, d, f,
> + PCI_BASE_ADDRESS_0 + bar_idx*4, bar);
>
> - pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0, ~0u);
> - len = pci_conf_read32(0, b, d, f, PCI_BASE_ADDRESS_0);
> - pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4, bar);
> + /* Not 8 bytes */
> + if ( (len & 0xffff) != 0xfff9 )
If you touch this, please use suitable manifest constants here too.
Jan
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2013-11-20 9:00 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-11-20 0:54 [PATCH V3] ns16550: Add support for UART present in Broadcom TruManage capable NetXtreme chips Aravind Gopalakrishnan
2013-11-20 9:00 ` Jan Beulich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).