[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] ns16550: enable PCI serial card usage
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1270026701 -3600 # Node ID 589d075ba2953123c1b39ecdbc190689ac6f443c # Parent ebd84be3420a4453b3024d3378d8d84b81f44118 ns16550: enable PCI serial card usage On some machine, there is no build-in serial port and no LPC connection. To use serial port, we have to plug in a serial card. Sometime BIOS doesn't enable the BARs for the PCI devices which lead to that Xen can't use the add-in serial port for early log print. This patch try to initialize the serial card and related PCI bridge to make it usable for xen. Usage: Step 1. boot into bare metal Linux, get the information for the PCI serial ports and the related PCI bridge. On my case: #lspci -v 00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev 90) (prog-if 01 [Subtractive decode]) Bus: primary=00, secondary=06, subordinate=06, sec-latency=32 I/O behind bridge: 00005000-00005fff 06:02.0 Serial controller: Lava Computer mfg Inc Lava DSerial-PCI Port A (prog-if 02 [16550]) Region 0: I/O ports at 5000 [size=8] Step 2. revise the grub.conf to include 'com1=115200,8n1,0xPPPP,0,<port-bdf>,<bridge-bdf> console=com1' for xen cmdline. The 0xPPPP is the base I/O port address got for the serial port in bare metal Linux. For my case, it is 0x5000. The 0 after 0xPPPP means enable polling model for the serial port. The <port-bdf> is the serial port BDF, 06:02.0 in my case; the <bridge-bdf> is the bridge BDF bebind which the serial card locates, 00:1e.0 for my case. Signed-off-by: Wei Gang <gang.wei@xxxxxxxxx> --- xen/drivers/char/ns16550.c | 53 +++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 51 insertions(+), 2 deletions(-) diff -r ebd84be3420a -r 589d075ba295 xen/drivers/char/ns16550.c --- a/xen/drivers/char/ns16550.c Tue Mar 30 18:31:39 2010 +0100 +++ b/xen/drivers/char/ns16550.c Wed Mar 31 10:11:41 2010 +0100 @@ -19,7 +19,7 @@ /* * Configure serial port with a string: - * <baud>[/<clock_hz>][,DPS[,<io-base>[,<irq>]]]. + * <baud>[/<clock_hz>][,DPS[,<io-base>[,<irq>[,<port-bdf>[,<bridge-bdf>]]]]]. * The tail of the string can be omitted if platform defaults are sufficient. * If the baud rate is pre-configured, perhaps by a bootloader, then 'auto' * can be specified in place of a numeric baud rate. Polled mode is specified @@ -39,7 +39,12 @@ static struct ns16550 { /* UART with no IRQ line: periodically-polled I/O. */ struct timer timer; unsigned int timeout_ms; - int probing, intr_works; + bool_t probing, intr_works; + /* PCI card parameters. */ + unsigned int pb_bdf[3]; /* pci bridge BDF */ + unsigned int ps_bdf[3]; /* pci serial port BDF */ + bool_t pb_bdf_enable; /* if =1, pb-bdf effective, port behind bridge */ + bool_t ps_bdf_enable; /* if =1, ps_bdf effective, port on pci card */ } ns16550_com[2] = { { 0 } }; /* Register offsets */ @@ -204,11 +209,28 @@ static int ns16550_getc(struct serial_po return 1; } +static void pci_serial_early_init(struct ns16550 *uart) +{ + if ( !uart->ps_bdf_enable ) + return; + + if ( uart->pb_bdf_enable ) + pci_conf_write16(uart->pb_bdf[0], uart->pb_bdf[1], uart->pb_bdf[2], + 0x1c, (uart->io_base & 0xF000) | ((uart->io_base & 0xF000) >> 8)); + + pci_conf_write32(uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2], + 0x10, uart->io_base | 0x1); + pci_conf_write16(uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2], + 0x4, 0x1); +} + static void __devinit ns16550_init_preirq(struct serial_port *port) { struct ns16550 *uart = port->uart; unsigned char lcr; unsigned int divisor; + + pci_serial_early_init(uart); /* I/O ports are distinguished by their size (16 bits). */ if ( uart->io_base >= 0x10000 ) @@ -336,6 +358,19 @@ static int __init parse_parity_char(int return 0; } +static void __init parse_pci_bdf(const char **conf, unsigned int bdf[3]) +{ + bdf[0] = simple_strtoul(*conf, conf, 16); + if ( **conf != ':' ) + return; + (*conf)++; + bdf[1] = simple_strtoul(*conf, conf, 16); + if ( **conf != '.' ) + return; + (*conf)++; + bdf[2] = simple_strtoul(*conf, conf, 16); +} + static int __init check_existence(struct ns16550 *uart) { unsigned char status, scratch, scratch2, scratch3; @@ -347,6 +382,8 @@ static int __init check_existence(struct if ( uart->io_base >= 0x10000 ) return 1; + pci_serial_early_init(uart); + /* * Do a simple existence test first; if we fail this, * there's no point trying anything else. @@ -428,6 +465,18 @@ static void __init ns16550_parse_port_co { conf++; uart->irq = simple_strtoul(conf, &conf, 10); + if ( *conf == ',' ) + { + conf++; + uart->ps_bdf_enable = 1; + parse_pci_bdf(&conf, &uart->ps_bdf[0]); + if ( *conf == ',' ) + { + conf++; + uart->pb_bdf_enable = 1; + parse_pci_bdf(&conf, &uart->pb_bdf[0]); + } + } } } _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog |
Lists.xenproject.org is hosted with RackSpace, monitoring our |