From 8b86714af8ccf3fb1b313428c5bc88d9977524f9 Mon Sep 17 00:00:00 2001 From: Victor Sun Date: Tue, 8 Sep 2020 15:29:16 +0800 Subject: [PATCH] HV: fix uart hang issue caused by bdf overridden On a PCI type HV uart, the bdf value is in a union together with mmio_base_vaddr, then the value would be overridden by mmio_base_addr in uart16550_init(), result in is_pci_dbg_uart() returns a wrong value and then uart hang. Tracked-On: #5288 Signed-off-by: Victor Sun Acked-by: Eddie Dong --- hypervisor/debug/uart16550.c | 50 ++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/hypervisor/debug/uart16550.c b/hypervisor/debug/uart16550.c index 500518d07..06672b492 100644 --- a/hypervisor/debug/uart16550.c +++ b/hypervisor/debug/uart16550.c @@ -20,8 +20,13 @@ struct console_uart { enum serial_dev_type type; union { uint16_t port_address; - union pci_bdf bdf; - void *mmio_base_vaddr; + union { + struct { + union pci_bdf bdf; + void *cached_mmio_base_va; + } pci; + void *mmio_base_vaddr; + } mmio; }; spinlock_t rx_lock; @@ -41,14 +46,14 @@ static struct console_uart uart = { static struct console_uart uart = { .enabled = true, .type = PCI, - .bdf.value = CONFIG_SERIAL_PCI_BDF, + .mmio.pci.bdf.value = CONFIG_SERIAL_PCI_BDF, .reg_width = 4, }; #elif defined(CONFIG_SERIAL_MMIO_BASE) static struct console_uart uart = { .enabled = true, .type = MMIO, - .mmio_base_vaddr = (void *)CONFIG_SERIAL_MMIO_BASE, + .mmio.mmio_base_vaddr = (void *)CONFIG_SERIAL_MMIO_BASE, .reg_width = 1, }; #endif @@ -63,9 +68,9 @@ static inline uint32_t uart16550_read_reg(struct console_uart uart, uint16_t reg if (uart.type == PIO) { return pio_read8(uart.port_address + (reg_idx * uart.reg_width)); } else if (uart.type == PCI) { - return mmio_read32(uart.mmio_base_vaddr + (reg_idx * uart.reg_width)); + return mmio_read32(uart.mmio.pci.cached_mmio_base_va + (reg_idx * uart.reg_width)); } else { - return mmio_read8(uart.mmio_base_vaddr + (reg_idx * uart.reg_width)); + return mmio_read8(uart.mmio.mmio_base_vaddr + (reg_idx * uart.reg_width)); } } @@ -77,9 +82,9 @@ static inline void uart16550_write_reg(struct console_uart uart, uint32_t val, u if (uart.type == PIO) { pio_write8(val, uart.port_address + (reg_idx * uart.reg_width)); } else if (uart.type == PCI) { - mmio_write32(val, uart.mmio_base_vaddr + (reg_idx * uart.reg_width)); + mmio_write32(val, uart.mmio.pci.cached_mmio_base_va + (reg_idx * uart.reg_width)); } else { - mmio_write8(val, uart.mmio_base_vaddr + (reg_idx * uart.reg_width)); + mmio_write8(val, uart.mmio.mmio_base_vaddr + (reg_idx * uart.reg_width)); } } @@ -121,20 +126,33 @@ static void uart16550_set_baud_rate(uint32_t baud_rate) void uart16550_init(bool early_boot) { + void *mmio_base_va = NULL; + if (!uart.enabled) { return; } - if (!early_boot && (uart.type != PIO)) { - uart.mmio_base_vaddr = hpa2hva(hva2hpa_early(uart.mmio_base_vaddr)); - hv_access_memory_region_update((uint64_t)uart.mmio_base_vaddr, PDE_SIZE); + if (!early_boot) { + if (uart.type == MMIO) { + mmio_base_va = hpa2hva(hva2hpa_early(uart.mmio.mmio_base_vaddr)); + } else if (uart.type == PCI) { + mmio_base_va = hpa2hva(hva2hpa_early(uart.mmio.pci.cached_mmio_base_va)); + } + if (mmio_base_va != NULL) { + hv_access_memory_region_update((uint64_t)mmio_base_va, PDE_SIZE); + } return; } /* if configure serial PCI BDF, get its base MMIO address */ if (uart.type == PCI) { - uart.mmio_base_vaddr = - hpa2hva_early(pci_pdev_read_cfg(uart.bdf, pci_bar_offset(0), 4U) & PCIM_BAR_MEM_BASE); + uart.mmio.pci.cached_mmio_base_va = + hpa2hva_early(pci_pdev_read_cfg(uart.mmio.pci.bdf, pci_bar_offset(0), 4U) & PCIM_BAR_MEM_BASE); + if (uart.mmio.pci.cached_mmio_base_va == NULL) { + /* in case the PCI UART BAR is reset to 0 after boot */ + uart.enabled = false; + return; + } } spinlock_init(&uart.rx_lock); spinlock_init(&uart.tx_lock); @@ -223,10 +241,10 @@ void uart16550_set_property(bool enabled, enum serial_dev_type uart_type, uint64 if (uart_type == PIO) { uart.port_address = data; } else if (uart_type == PCI) { - uart.bdf.value = data; + uart.mmio.pci.bdf.value = data; uart.reg_width = 4; } else if (uart_type == MMIO) { - uart.mmio_base_vaddr = (void *)data; + uart.mmio.mmio_base_vaddr = (void *)data; uart.reg_width = 1; } } @@ -236,7 +254,7 @@ bool is_pci_dbg_uart(union pci_bdf bdf_value) bool ret = false; if (uart.enabled && (uart.type == PCI)) { - if (bdf_value.value == uart.bdf.value) { + if (bdf_value.value == uart.mmio.pci.bdf.value) { ret = true; } }