vUART: change S5 vUART resource

This patch is to change the vUART resource occupied by S5 function
between Service VM and guest VM to avoid the standard UART port
conflict when legacy UART passthrough to guest VM.

Tracked-On: #8622

Signed-off-by: YuanXin-Intel <xin.yuan@intel.com>
Reviewed-by: Junjie Mao <junjie.mao@intel.com>
Reviewed-by: Jian Jun Chen <jian.jun.chen@intel.com>
This commit is contained in:
YuanXin-Intel 2024-07-07 21:34:44 -04:00 committed by acrnsi-robot
parent 87dffcbc92
commit e4429d632b
5 changed files with 62 additions and 17 deletions

View File

@ -59,7 +59,7 @@ SYSRES_IO(NMISC_PORT, 1);
static struct pci_vdev *lpc_bridge;
#define LPC_UART_NUM 4
#define LPC_UART_NUM 5
static struct lpc_uart_vdev {
struct uart_vdev *uart;
const char *opts;
@ -67,19 +67,23 @@ static struct lpc_uart_vdev {
int irq;
int enabled; /* enabled/configured by user */
} lpc_uart_vdev[LPC_UART_NUM];
#define LPC_S5_UART_NAME "COM5"
static const char *lpc_uart_names[LPC_UART_NUM] = { "COM1", "COM2", "COM3", "COM4" };
static const char *lpc_uart_names[LPC_UART_NUM] = { "COM1", "COM2", "COM3", "COM4", LPC_S5_UART_NAME};
/*
* LPC device configuration is in the following form:
* <lpc_device_name>[,<options>]
* For e.g. "com1,stdio"
* For S5 e.g. "com5,/dev/pts/0,0x9000,5"
*/
int
lpc_device_parse(const char *opts)
{
int unit, error;
char *str, *cpy, *lpcdev;
char *lpcopt, *lpcport, *endptr;
int s5_port = 0, s5_irq = 0;
error = -1;
str = cpy = strdup(opts);
@ -88,7 +92,25 @@ lpc_device_parse(const char *opts)
for (unit = 0; unit < LPC_UART_NUM; unit++) {
if (strcasecmp(lpcdev, lpc_uart_names[unit]) == 0) {
lpc_uart_vdev[unit].enabled = 1;
lpc_uart_vdev[unit].opts = str;
if(strcasecmp(lpcdev,LPC_S5_UART_NAME) == 0){
lpcopt = strsep(&str,",");
if(lpcopt != NULL){
lpc_uart_vdev[unit].opts = lpcopt;
}
lpcport = strsep(&str, ",");
if(lpcport != NULL){
if(dm_strtoul(lpcport, &endptr, 0, (long unsigned int*)&s5_port))
goto done;
if(dm_strtoul(str, &endptr, 0, (long unsigned int*)&s5_irq))
goto done;
}
if((s5_port != 0) && (s5_irq != 0)){
uart_legacy_reinit_res(unit, s5_port, s5_irq);
}
}
else{
lpc_uart_vdev[unit].opts = str;
}
error = 0;
goto done;
}

View File

@ -56,6 +56,8 @@
#define COM3_IRQ 6
#define COM4_BASE 0x2E8
#define COM4_IRQ 7
#define COM5_BASE 0x9000 /*for S5 connection*/
#define COM5_IRQ 10
#define DEFAULT_RCLK 1843200
#define DEFAULT_BAUD 9600
@ -89,6 +91,7 @@ static struct {
{ COM2_BASE, COM2_IRQ, false},
{ COM3_BASE, COM3_IRQ, false},
{ COM4_BASE, COM4_IRQ, false},
{ COM5_BASE, COM5_IRQ, false},
};
#define UART_NLDEVS (ARRAY_SIZE(uart_lres))
@ -624,6 +627,18 @@ uart_legacy_alloc(int which, int *baseaddr, int *irq)
return 0;
}
int
uart_legacy_reinit_res(int which, int baseaddr, int irq)
{
if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse)
return -1;
uart_lres[which].baseaddr = baseaddr;
uart_lres[which].irq = irq;
return 0;
}
void
uart_legacy_dealloc(int which)
{

View File

@ -36,6 +36,7 @@ struct uart_vdev;
typedef void (*uart_intr_func_t)(void *arg);
int uart_legacy_alloc(int unit, int *ioaddr, int *irq);
int uart_legacy_reinit_res(int which, int baseaddr, int irq);
void uart_legacy_dealloc(int which);
uint8_t uart_read(struct uart_vdev *uart, int offset);
void uart_write(struct uart_vdev *uart, int offset, uint8_t value);

View File

@ -74,6 +74,9 @@ def alloc_vuart_connection_irqs(board_etree, scenario_etree, allocation_etree):
remove_irq(irq_list, 3)
if 4 in irq_list:
remove_irq(irq_list, 4)
else:
if 14 in irq_list:
remove_irq(irq_list, 14)
vuart_id = 1
legacy_vuart_irq = "0"
vmname = get_node("./name/text()", vm_node)
@ -97,7 +100,7 @@ def alloc_vuart_connection_irqs(board_etree, scenario_etree, allocation_etree):
vuart_id = vuart_id + 1
# Allocate irq for S5 vuart, we have to use the irq of COM2
if load_order != "SERVICE_VM":
legacy_vuart_irq = alloc_standard_irq("0x2F8")
legacy_vuart_irq = alloc_irq(irq_list)
create_vuart_irq_node(allocation_etree, get_node("./@id", vm_node), load_order, str(vuart_id), legacy_vuart_irq)
vuart_id = vuart_id + 1

View File

@ -8,9 +8,11 @@
import sys
import acrn_config_utilities, lib.error
from acrn_config_utilities import get_node
from collections import defaultdict
# The COM1 was used for console vUART, so we alloc io_port frome COM2~COM4
service_port_list = list(range(0x9000, 0x9100, 8))
val = lambda:list(range(0x9000, 0x9100, 8))
vm_port_list = defaultdict(val)
def create_s5_vuart_connection(allocation_etree, service_vm_name, service_vm_port, user_vm_name, user_vm_port):
vuart_connections_node = get_node(f"/acrn-config/hv/vuart_connections", allocation_etree)
@ -49,23 +51,25 @@ def get_console_vuart_port(scenario_etree, vm_name):
def alloc_free_port(scenario_etree, load_order, vm_name):
port_list = scenario_etree.xpath(f"//endpoint[vm_name = '{vm_name}']/io_port/text()")
if load_order == "SERVICE_VM":
vm_id = int(get_node(f"//vm[load_order = 'SERVICE_VM']/@id", scenario_etree))
else:
vm_id = int(get_node(f"//vm[name = '{vm_name}']/@id", scenario_etree))
console_port = get_console_vuart_port(scenario_etree, vm_name)
if console_port is not None:
port_list.append(console_port.replace("U", ""))
tmp_list = []
for port in port_list:
tmp_list.append(int(port, 16))
if load_order == "SERVICE_VM":
tmp_list = []
for port in port_list:
tmp_list.append(int(port, 16))
global service_port_list
service_port_list = list(set(service_port_list) - set(tmp_list))
service_port_list.sort()
port = hex(service_port_list[0])
service_port_list.remove(service_port_list[0])
return str(port).upper()
else:
return "0x2F8"
global vm_port_list
vm_port_list[vm_id] = list(set(vm_port_list[vm_id]) - set(tmp_list))
vm_port_list[vm_id].sort()
port = hex(vm_port_list[vm_id][0])
vm_port_list[vm_id].remove(vm_port_list[vm_id][0])
return str(port).upper()
def alloc_vuart_connection_info(board_etree, scenario_etree, allocation_etree):
user_vm_list = scenario_etree.xpath(f"//vm[load_order != 'SERVICE_VM']")