From 020692241661be8c445bcd4087cf566e851ae3d5 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 21 Feb 2014 11:43:51 -0500 Subject: [PATCH 6/6] pci/assign-buses: Suspend/resume the console device and update bus. When we suspend and resume the console devices we need the proper bus number. With us altering the bus numbers we need to update the bus numbers otherwise the console device might reprogram the wrong device. Signed-off-by: Konrad Rzeszutek Wilk --- xen/drivers/char/ehci-dbgp.c | 24 +++++++++++++++++++++++- xen/drivers/char/ns16550.c | 37 +++++++++++++++++++++++++++++++++++++ xen/drivers/char/serial.c | 17 +++++++++++++++++ xen/drivers/passthrough/pci.c | 10 +++++++++- xen/include/xen/serial.h | 7 +++++++ 5 files changed, 93 insertions(+), 2 deletions(-) diff --git a/xen/drivers/char/ehci-dbgp.c b/xen/drivers/char/ehci-dbgp.c index b900d60..a85b62e 100644 --- a/xen/drivers/char/ehci-dbgp.c +++ b/xen/drivers/char/ehci-dbgp.c @@ -1437,7 +1437,27 @@ static void ehci_dbgp_resume(struct serial_port *port) ehci_dbgp_setup_preirq(dbgp); ehci_dbgp_setup_postirq(dbgp); } +static int __init ehci_dbgp_is_owner(struct serial_port *port, u8 bus, u8 devfn) +{ + struct ehci_dbgp *dbgp = port->uart; + if ( dbgp->bus == bus && dbgp->slot == PCI_SLOT(devfn) && + dbgp->func == PCI_FUNC(devfn)) + return 1; + return -ENODEV; +} +static int __init ehci_dbgp_update_bus(struct serial_port *port, u8 old_bus, + u8 devfn, u8 new_bus) +{ + struct ehci_dbgp *dbgp; + + if ( ehci_dbgp_is_owner (port, old_bus, devfn) < 0 ) + return -ENODEV; + + dbgp = port->uart; + dbgp->bus = new_bus; + return 1; +} static struct uart_driver __read_mostly ehci_dbgp_driver = { .init_preirq = ehci_dbgp_init_preirq, .init_postirq = ehci_dbgp_init_postirq, @@ -1447,7 +1467,9 @@ static struct uart_driver __read_mostly ehci_dbgp_driver = { .tx_ready = ehci_dbgp_tx_ready, .putc = ehci_dbgp_putc, .flush = ehci_dbgp_flush, - .getc = ehci_dbgp_getc + .getc = ehci_dbgp_getc, + .is_owner = ehci_dbgp_is_owner, + .update_bus = ehci_dbgp_update_bus, }; static struct ehci_dbgp ehci_dbgp = { .state = dbgp_unsafe, .phys_port = 1 }; diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c index e7cb0ba..8820fb9 100644 --- a/xen/drivers/char/ns16550.c +++ b/xen/drivers/char/ns16550.c @@ -462,7 +462,40 @@ static const struct vuart_info *ns16550_vuart_info(struct serial_port *port) return &uart->vuart; } #endif +#ifdef HAS_PCI +static int __init ns16550_is_owner(struct serial_port *port, u8 bus, u8 devfn) +{ + struct ns16550 *uart = port->uart; + + if ( uart->ps_bdf_enable ) + { + if ( (bus == uart->ps_bdf[0]) && (uart->ps_bdf[1] == PCI_SLOT(devfn)) && + (uart->ps_bdf[2] == PCI_FUNC(devfn)) ) + return 1; + } + if ( uart->pb_bdf_enable ) + { + if ( (bus == uart->pb_bdf[0]) && (uart->pb_bdf[1] == PCI_SLOT(devfn)) && + (uart->pb_bdf[2] == PCI_FUNC(devfn)) ) + return 1; + } + return -ENODEV; +} +static int __init ns16550_update_bus(struct serial_port *port, u8 old_bus, + u8 devfn, u8 new_bus) +{ + struct ns16550 *uart; + if ( ns16550_is_owner(port, old_bus, devfn ) < 0 ) + return -ENODEV; + uart = port->uart; + if ( uart->ps_bdf_enable ) + uart->ps_bdf[0]= new_bus; + if ( uart->pb_bdf_enable ) + uart->pb_bdf[0] = new_bus; + return 1; +} +#endif static struct uart_driver __read_mostly ns16550_driver = { .init_preirq = ns16550_init_preirq, .init_postirq = ns16550_init_postirq, @@ -479,6 +512,10 @@ static struct uart_driver __read_mostly ns16550_driver = { #ifdef CONFIG_ARM .vuart_info = ns16550_vuart_info, #endif +#ifdef HAS_PCI + .is_owner = ns16550_is_owner, + .update_bus = ns16550_update_bus, +#endif }; static int __init parse_parity_char(int c) diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index 9b006f2..c620352 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -518,6 +518,23 @@ const struct vuart_info *serial_vuart_info(int idx) return NULL; } +int __init serial_is_owner(u8 bus, u8 devfn) +{ + int i; + for ( i = 0; i < ARRAY_SIZE(com); i++ ) + if ( com[i].driver->is_owner ) + return com[i].driver->is_owner(&com[i], bus, devfn); + + return 0; +} +int __init serial_update_bus(u8 old_bus, u8 devfn, u8 new_bus) +{ + int i; + for ( i = 0; i < ARRAY_SIZE(com); i++ ) + if ( com[i].driver->update_bus ) + return com[i].driver->update_bus(&com[i], old_bus, devfn, new_bus); + return 0; +} void serial_suspend(void) { int i; diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index ba852bd..e6d7316 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -1000,6 +1000,7 @@ static int __init _setup_dom0_pci_devices(struct pci_seg *pseg, void *arg) } /* Move this to its own file */ +#include #define DEBUG 1 static void parse_pci_param(char *s); custom_param("pci", parse_pci_param); @@ -1588,7 +1589,14 @@ static void __init update_console_devices(struct early_pci_bus *parent) { if ( dev->is_ehci || dev->is_serial || dev->is_bridge ) { - ;/* TODO */ + int rc = 0; + if ( serial_is_owner(parent->old_number , dev->devfn ) < 0 ) + continue; + rc = serial_update_bus(parent->old_number, dev->devfn, parent->number); + if ( verbose ) + printk("%02x:%02x.%u bus %x -> %x, rc=%d\n", parent->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + parent->old_number, parent->number, rc); } } list_for_each_entry( bus, &parent->children, next ) diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index f38c9b7..08b68e0 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -85,6 +85,10 @@ struct uart_driver { const struct dt_irq *(*dt_irq_get)(struct serial_port *); /* Get serial information */ const struct vuart_info *(*vuart_info)(struct serial_port *); + /* Check if the BDF matches this device */ + int (*is_owner)(struct serial_port *, u8 , u8); + /* Update its BDF due to bus number changing. devfn still same. */ + int (*update_bus)(struct serial_port *, u8, u8, u8); }; /* 'Serial handles' are composed from the following fields. */ @@ -141,6 +145,9 @@ const struct dt_irq *serial_dt_irq(int idx); /* Retrieve basic UART information to emulate it (base address, size...) */ const struct vuart_info* serial_vuart_info(int idx); +int serial_is_owner(u8 bus, u8 devfn); +int serial_update_bus(u8 old_bus, u8 devfn, u8 bus); + /* Serial suspend/resume. */ void serial_suspend(void); void serial_resume(void); -- 1.8.3.1