>From fa86138d42b1976b61485c886f1ba280dd23c29d Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 21 Feb 2014 11:43:51 -0500 Subject: [PATCH 4/5] pci/assign-buses: Suspend/resume the console device and update bus (v2). 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 | 17 ++++++++++++++++- xen/include/xen/serial.h | 7 +++++++ 5 files changed, 100 insertions(+), 2 deletions(-) diff --git a/xen/drivers/char/ehci-dbgp.c b/xen/drivers/char/ehci-dbgp.c index 3feeafe..3266307 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 b2b5f56..51b71ee 100644 --- a/xen/drivers/char/ns16550.c +++ b/xen/drivers/char/ns16550.c @@ -821,7 +821,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, @@ -835,6 +868,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 c583a48..f7b8178 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -543,6 +543,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 62b5f85..d7bdbd5 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -1098,6 +1098,7 @@ static int __hwdom_init _setup_hwdom_pci_devices(struct pci_seg *pseg, void *arg } /* Move this to its own file */ +#include #define DEBUG 1 struct early_pci_bus; @@ -1661,7 +1662,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 ) @@ -1722,6 +1730,10 @@ void __init early_pci_reassign_busses(void) } printk("Re-assigning busses to make space for %d bus numbers.\n", adjust); + /* Walk all the devices, disable serial and ehci */ + if ( !verbose) + serial_suspend(); + /* Walk all the bridges, disable forwarding */ /* Walk all bridges, reprogram with max (so new primary, secondary and such. */ list_for_each_entry( bus, &early_buses_list, next ) @@ -1733,6 +1745,9 @@ void __init early_pci_reassign_busses(void) list_for_each_entry( bus, &early_buses_list, next ) update_console_devices(bus); + if ( !verbose ) + serial_resume(); + print_devices(); out: early_free_all(); diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 1212a12..2ba9da7 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -87,6 +87,10 @@ struct uart_driver { void (*stop_tx)(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. */ @@ -140,6 +144,9 @@ int serial_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); -- 2.5.5