mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-23 05:57:33 +00:00
hv: debug: Enable MMIO UART support
New board, EHL CRB, does not have legacy port IO UART. Even the PCI UART are not work due to BIOS's bug workaround(the BARs on LPSS PCI are reset after BIOS hand over control to OS). For ACRN console usage, expose the debug UART via ACPI PnP device (access by MMIO) and add support in hypervisor debug code. Another special thing is that register width of UART of EHL CRB is 1byte. Introduce reg_width for each struct console_uart. Tracked-On: #4937 Signed-off-by: Yin Fengwei <fengwei.yin@intel.com> Signed-off-by: Shuo A Liu <shuo.a.liu@intel.com>
This commit is contained in:
parent
0c07999ec2
commit
d0e06c4f80
@ -126,6 +126,11 @@ config SERIAL_LEGACY
|
||||
Select this if the serial port shall be accessed via legacy port in/out
|
||||
instructions.
|
||||
|
||||
config SERIAL_MMIO
|
||||
bool "MMIO"
|
||||
help
|
||||
Select this if the serial port shall be accessed via MMIO registers.
|
||||
|
||||
endchoice
|
||||
|
||||
config SERIAL_PCI_BDF
|
||||
@ -144,6 +149,13 @@ config SERIAL_PIO_BASE
|
||||
The base address of the serial ports. This is logically 16-bit but used
|
||||
as a 64-bit integer.
|
||||
|
||||
config SERIAL_MMIO_BASE
|
||||
hex "Base address of MMIO UART"
|
||||
depends on SERIAL_MMIO
|
||||
default 0xfe040000
|
||||
help
|
||||
The base address of the MMIO serial port.
|
||||
|
||||
config CONSOLE_LOGLEVEL_DEFAULT
|
||||
int "Default loglevel on the serial console"
|
||||
depends on !RELEASE
|
||||
|
@ -15,57 +15,49 @@
|
||||
|
||||
#define MAX_CMD_LEN 64
|
||||
|
||||
static const char * const cmd_list[] = {
|
||||
"uart=disabled", /* to disable uart */
|
||||
"uart=port@", /* like uart=port@0x3F8 */
|
||||
"uart=bdf@", /*like: uart=bdf@0:18.2, it is for ttyS2 */
|
||||
};
|
||||
|
||||
enum IDX_CMD_DBG {
|
||||
IDX_DISABLE_UART,
|
||||
IDX_PORT_UART,
|
||||
IDX_PCI_UART,
|
||||
|
||||
IDX_MAX_CMD,
|
||||
static struct uart_cmd {
|
||||
const char *const str;
|
||||
int type;
|
||||
} cmd_list[] = {
|
||||
{ "uart=port@", PIO }, /* uart=port@0x3F8 */
|
||||
{ "uart=bdf@", PCI }, /* uart=bdf@0:18.2 */
|
||||
{ "uart=mmio@", MMIO }, /* uart=mmio@0xfe040000 */
|
||||
{ "uart=disabled", INVALID }
|
||||
};
|
||||
|
||||
bool handle_dbg_cmd(const char *cmd, int32_t len)
|
||||
{
|
||||
int32_t i;
|
||||
bool handled = false;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < IDX_MAX_CMD; i++) {
|
||||
int32_t tmp = strnlen_s(cmd_list[i], MAX_CMD_LEN);
|
||||
for (i = 0; i < ARRAY_SIZE(cmd_list); i++) {
|
||||
int32_t tmp = strnlen_s(cmd_list[i].str, MAX_CMD_LEN);
|
||||
int type = cmd_list[i].type;
|
||||
|
||||
/*cmd prefix should be same with one in cmd_list */
|
||||
/* cmd prefix should be same with one in cmd_list */
|
||||
if (len < tmp)
|
||||
continue;
|
||||
|
||||
if (strncmp(cmd_list[i], cmd, tmp) != 0)
|
||||
if (strncmp(cmd_list[i].str, cmd, tmp) != 0)
|
||||
continue;
|
||||
|
||||
if (i == IDX_DISABLE_UART) {
|
||||
if (type == INVALID) {
|
||||
/* set uart disabled*/
|
||||
uart16550_set_property(false, false, 0UL);
|
||||
} else if (i == IDX_PORT_UART) {
|
||||
uart16550_set_property(false, type, 0UL);
|
||||
} else if (type == PIO) {
|
||||
uint64_t addr = strtoul_hex(cmd + tmp);
|
||||
|
||||
if (addr > MAX_PORT) {
|
||||
addr = DEFAULT_UART_PORT;
|
||||
}
|
||||
|
||||
uart16550_set_property(true, true, addr);
|
||||
|
||||
} else if (i == IDX_PCI_UART) {
|
||||
uart16550_set_property(true, false, (uint64_t)(cmd+tmp));
|
||||
uart16550_set_property(true, type, addr);
|
||||
} else if (type == PCI) {
|
||||
uart16550_set_property(true, type, (uint64_t)(cmd+tmp));
|
||||
} else {
|
||||
/* No other state currently, do nothing */
|
||||
uint64_t addr = strtoul_hex(cmd + tmp);
|
||||
uart16550_set_property(true, type, addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (i < IDX_MAX_CMD) {
|
||||
handled = true;
|
||||
}
|
||||
|
||||
return handled;
|
||||
return i < ARRAY_SIZE(cmd_list)? true : false;
|
||||
}
|
||||
|
@ -16,29 +16,41 @@
|
||||
|
||||
struct console_uart {
|
||||
bool enabled;
|
||||
bool serial_port_mapped;
|
||||
|
||||
enum serial_dev_type type;
|
||||
union {
|
||||
uint16_t port_address;
|
||||
void *mmio_base_vaddr;
|
||||
};
|
||||
|
||||
spinlock_t rx_lock;
|
||||
spinlock_t tx_lock;
|
||||
|
||||
uint32_t reg_width;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SERIAL_PIO_BASE)
|
||||
static struct console_uart uart = {
|
||||
.enabled = true,
|
||||
.serial_port_mapped = true,
|
||||
.type = PIO,
|
||||
.port_address = CONFIG_SERIAL_PIO_BASE,
|
||||
.reg_width = 1,
|
||||
};
|
||||
static char pci_bdf_info[MAX_BDF_LEN + 1U];
|
||||
#elif defined(CONFIG_SERIAL_PCI_BDF)
|
||||
static struct console_uart uart = {
|
||||
.enabled = true,
|
||||
.type = PCI,
|
||||
.reg_width = 4,
|
||||
};
|
||||
static char pci_bdf_info[MAX_BDF_LEN + 1U] = CONFIG_SERIAL_PCI_BDF;
|
||||
#else
|
||||
static struct console_uart uart;
|
||||
#elif defined(CONFIG_SERIAL_MMIO_BASE)
|
||||
static struct console_uart uart = {
|
||||
.enabled = true,
|
||||
.type = MMIO,
|
||||
.mmio_base_vaddr = (void *)CONFIG_SERIAL_MMIO_BASE,
|
||||
.reg_width = 1,
|
||||
};
|
||||
static char pci_bdf_info[MAX_BDF_LEN + 1U];
|
||||
#endif
|
||||
|
||||
@ -77,10 +89,12 @@ static uint16_t get_pci_bdf_value(char *bdf)
|
||||
*/
|
||||
static inline uint32_t uart16550_read_reg(struct console_uart uart, uint16_t reg_idx)
|
||||
{
|
||||
if (uart.serial_port_mapped) {
|
||||
return pio_read8(uart.port_address + reg_idx);
|
||||
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));
|
||||
} else {
|
||||
return mmio_read32((uint32_t *)uart.mmio_base_vaddr + reg_idx);
|
||||
return mmio_read8(uart.mmio_base_vaddr + (reg_idx * uart.reg_width));
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,10 +103,12 @@ static inline uint32_t uart16550_read_reg(struct console_uart uart, uint16_t reg
|
||||
*/
|
||||
static inline void uart16550_write_reg(struct console_uart uart, uint32_t val, uint16_t reg_idx)
|
||||
{
|
||||
if (uart.serial_port_mapped) {
|
||||
pio_write8(val, uart.port_address + reg_idx);
|
||||
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));
|
||||
} else {
|
||||
mmio_write32(val, (uint32_t *)uart.mmio_base_vaddr + reg_idx);
|
||||
mmio_write8(val, uart.mmio_base_vaddr + (reg_idx * uart.reg_width));
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,19 +154,18 @@ void uart16550_init(bool early_boot)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!early_boot && !uart.serial_port_mapped) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if configure serial PCI BDF, get its base MMIO address */
|
||||
if (!uart.serial_port_mapped) {
|
||||
if (uart.type == PCI) {
|
||||
serial_pci_bdf.value = get_pci_bdf_value(pci_bdf_info);
|
||||
uart.mmio_base_vaddr =
|
||||
hpa2hva_early(pci_pdev_read_cfg(serial_pci_bdf, pci_bar_offset(0), 4U) & PCIM_BAR_MEM_BASE);
|
||||
}
|
||||
|
||||
spinlock_init(&uart.rx_lock);
|
||||
spinlock_init(&uart.tx_lock);
|
||||
/* Enable TX and RX FIFOs */
|
||||
@ -230,16 +245,20 @@ size_t uart16550_puts(const char *buf, uint32_t len)
|
||||
return len;
|
||||
}
|
||||
|
||||
void uart16550_set_property(bool enabled, bool port_mapped, uint64_t base_addr)
|
||||
void uart16550_set_property(bool enabled, enum serial_dev_type uart_type, uint64_t base_addr)
|
||||
{
|
||||
uart.enabled = enabled;
|
||||
uart.serial_port_mapped = port_mapped;
|
||||
uart.type = uart_type;
|
||||
|
||||
if (port_mapped) {
|
||||
if (uart_type == PIO) {
|
||||
uart.port_address = base_addr;
|
||||
} else {
|
||||
} else if (uart_type == PCI) {
|
||||
const char *bdf = (const char *)base_addr;
|
||||
strncpy_s(pci_bdf_info, MAX_BDF_LEN + 1U, bdf, MAX_BDF_LEN);
|
||||
uart.reg_width = 4;
|
||||
} else if (uart_type == MMIO) {
|
||||
uart.mmio_base_vaddr = (void *)base_addr;
|
||||
uart.reg_width = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +266,7 @@ bool is_pci_dbg_uart(union pci_bdf bdf_value)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (uart.enabled && !uart.serial_port_mapped) {
|
||||
if (uart.enabled && (uart.type == PCI)) {
|
||||
if (bdf_value.value == serial_pci_bdf.value) {
|
||||
ret = true;
|
||||
}
|
||||
|
@ -127,10 +127,17 @@
|
||||
/* UART oscillator clock */
|
||||
#define UART_CLOCK_RATE 1843200U /* 1.8432 MHz */
|
||||
|
||||
enum serial_dev_type {
|
||||
INVALID,
|
||||
PIO,
|
||||
PCI,
|
||||
MMIO,
|
||||
};
|
||||
|
||||
void uart16550_init(bool early_boot);
|
||||
char uart16550_getc(void);
|
||||
size_t uart16550_puts(const char *buf, uint32_t len);
|
||||
void uart16550_set_property(bool enabled, bool port_mapped, uint64_t base_addr);
|
||||
void uart16550_set_property(bool enabled, enum serial_dev_type uart_type, uint64_t base_addr);
|
||||
bool is_pci_dbg_uart(union pci_bdf bdf_value);
|
||||
|
||||
#endif /* !UART16550_H */
|
||||
|
Loading…
Reference in New Issue
Block a user