mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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@intel.com>
This commit is contained in:
1 parent
5657c1d9cb
commit
f2ff5d6628
1 file changed
+51
-2
@@ -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,12 +209,29 @@ static int ns16550_getc(struct serial_port *port, char *pc)
|
||||
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 )
|
||||
uart->remapped_io_base = (char *)ioremap(uart->io_base, 8);
|
||||
@@ -336,6 +358,19 @@ static int __init parse_parity_char(int c)
|
||||
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 ns16550 *uart)
|
||||
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_config(
|
||||
{
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||