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

[Xen-devel] [PATCH]enable PCI serial card usage



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.

Finally, good luck to you.

Signed-off-by: Wei Gang <gang.wei@xxxxxxxxx>

diff -r 0475c567c708 xen/drivers/char/ns16550.c
--- a/xen/drivers/char/ns16550.c        Tue Mar 23 09:37:59 2010 +0000
+++ b/xen/drivers/char/ns16550.c        Wed Mar 24 17:03:58 2010 +0800
@@ -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
@@ -40,6 +40,11 @@ static struct ns16550 {
     struct timer timer;
     unsigned int timeout_ms;
     int probing, intr_works;
+    /* on pci card */
+    unsigned int pb_bdf[3]; /* pci bridge BDF */
+    unsigned int ps_bdf[3]; /* pci serial port BDF */
+    int pb_bdf_enable:1;    /* if =1, pb-bdf effective, port behind bridge */
+    int ps_bdf_enable:1;    /* 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]);
+                }
+            }
         }
     }
 

Attachment: pci_serial_v3.patch
Description: pci_serial_v3.patch

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

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