acrn-hypervisor/misc/config_tools/scenario_config/pci_dev_c.py
Yang,Yu-chu 0305640a5b config-tools: find the unused bdf based on first unused "dev"
Refine the logic of finding unused bdf for SOS ivshmem devices. First,
find the unused bdf based on if the "dev" is unused. Increase the "func"
for the next same type of emulated devices if the last assigned bdf
exists. Otherwise, start over looking for unused bdf based on "dev"
repeatedly.

Tracked-On: #5869
Signed-off-by: Yang,Yu-chu <yu-chu.yang@intel.com>
2021-04-09 15:11:51 +08:00

321 lines
14 KiB
Python

# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import re
from collections import namedtuple
import common
import scenario_cfg_lib
import board_cfg_lib
PCI_DEV_TYPE = ['PCI_DEV_TYPE_HVEMUL', 'PCI_DEV_TYPE_PTDEV']
class BusDevFunc(namedtuple(
"BusDevFunc", [
"bus",
"dev",
"func"])):
PATTERN = re.compile(r"(?P<bus>[0-9a-f]{2}):(?P<dev>[0-9a-f]{2})\.(?P<func>[0-7]{1})")
@classmethod
def from_str(cls, value):
if not(isinstance(value, str)):
raise ValueError("value must be a str: {}".format(type(value)))
match = cls.PATTERN.fullmatch(value)
if match:
return BusDevFunc(
bus=int(match.group("bus"), 16),
dev=int(match.group("dev"), 16),
func=int(match.group("func"), 16))
else:
raise ValueError("not a bdf: {!r}".format(value))
def __init__(self, *args, **kwargs):
if not (0x00 <= self.bus <= 0xff):
raise ValueError("Invalid bus number (0x00 ~ 0xff): {:#04x}".format(self.bus))
if not (0x00 <= self.dev <= 0x1f):
raise ValueError("Invalid device number (0x00 ~ 0x1f): {:#04x}".format(self.dev))
if not (0x0 <= self.func <= 0x7):
raise ValueError("Invalid function number (0 ~ 7): {:#x}".format(self.func))
def __str__(self):
return "{:02x}:{:02x}.{:x}".format(self.bus, self.dev, self.func)
def __repr__(self):
return "BusDevFunc.from_str({!r})".format(str(self))
def find_unused_bdf(used_bdf, case, last_bdf):
if case == "vuart":
# vuart device cannot detect function difference, find vbdf based on dev increment
for dev in range(0x20):
bdf = BusDevFunc(bus=0x00, dev=dev, func=0x0)
#if bdf not in used_bdf:
if all((bdf.dev != in_use_bdf.dev for in_use_bdf in used_bdf)):
return bdf
else:
if last_bdf == BusDevFunc(bus=0x00, dev=0x00, func=0x0) or last_bdf.func == 0x7:
for dev in range(0x20):
bdf = BusDevFunc(bus=0x00, dev=dev, func=0x0)
#if bdf not in used_bdf:
if all((bdf.dev != in_use_bdf.dev for in_use_bdf in used_bdf)):
return bdf
else:
bdf = last_bdf
for func in range(0x8):
bdf = BusDevFunc(bdf.bus, bdf.dev, func)
#if bdf not in used_bdf:
if bdf not in used_bdf:
return bdf
raise ValueError("Cannot find free bdf")
def add_instance_to_name(i_cnt, bdf, bar_attr):
if i_cnt == 0 and bar_attr.name.upper() == "HOST BRIDGE":
tmp_sub_name = "_".join(bar_attr.name.split()).upper()
else:
if '-' in bar_attr.name:
tmp_sub_name = common.undline_name(bar_attr.name) + "_" + str(i_cnt)
else:
tmp_sub_name = "_".join(bar_attr.name.split()).upper() + "_" + str(i_cnt)
board_cfg_lib.PCI_DEV_BAR_DESC.pci_dev_dic[bdf].name_w_i_cnt = tmp_sub_name
def generate_file(vm_info, config):
"""
Generate pci_dev.c for Pre-Launched VMs in a scenario.
:param config: it is pointer for for file write to
:return: None
"""
board_cfg_lib.parser_pci()
board_cfg_lib.parse_mem()
compared_bdf = []
sos_used_bdf = []
for cnt_sub_name in board_cfg_lib.SUB_NAME_COUNT.keys():
i_cnt = 0
for bdf, bar_attr in board_cfg_lib.PCI_DEV_BAR_DESC.pci_dev_dic.items():
if cnt_sub_name == bar_attr.name and bdf not in compared_bdf:
compared_bdf.append(bdf)
else:
continue
add_instance_to_name(i_cnt, bdf, bar_attr)
i_cnt += 1
for bdf in compared_bdf:
bdf_tuple = BusDevFunc.from_str(bdf)
sos_used_bdf.append(bdf_tuple)
# BDF 00:01.0 cannot be used in tgl
bdf_tuple = BusDevFunc(bus=0,dev=1,func=0)
sos_used_bdf.append(bdf_tuple)
vuarts = common.get_vuart_info(common.SCENARIO_INFO_FILE)
pci_vuarts_num = scenario_cfg_lib.get_pci_vuart_num(vuarts)
pci_vuart_enabled = False
for vm_i in common.VM_TYPES:
if pci_vuarts_num[vm_i] > 0:
pci_vuart_enabled = True
break
print("{}".format(scenario_cfg_lib.HEADER_LICENSE), file=config)
print("", file=config)
print("#include <x86/vm_config.h>", file=config)
print("#include <pci_devices.h>", file=config)
print("#include <vpci.h>", file=config)
print("#include <vbar_base.h>", file=config)
print("#include <x86/mmu.h>", file=config)
print("#include <x86/page.h>", file=config)
if pci_vuart_enabled:
print("#include <vmcs9900.h>", file=config)
# Insert header for share memory
if vm_info.shmem.shmem_enabled == 'y':
print("#include <ivshmem_cfg.h>", file=config)
# Insert comments and macros for passthrough devices
if any((p for _,p in vm_info.cfg_pci.pci_devs.items())):
print("", file=config)
print("/*", file=config)
print(" * TODO: remove PTDEV macro and add DEV_PRIVINFO macro to initialize pbdf for", file=config)
print(" * passthrough device configuration and shm_name for ivshmem device configuration.", file=config)
print(" */", file=config)
print("#define PTDEV(PCI_DEV)\t\tPCI_DEV, PCI_DEV##_VBAR",file=config)
print("", file=config)
print("/*", file=config)
print(" * TODO: add DEV_PCICOMMON macro to initialize emu_type, vbdf and vdev_ops", file=config)
print(" * to simplify the code.", file=config)
print(" */", file=config)
if pci_vuart_enabled:
print("#define INVALID_PCI_BASE\t0U",file=config)
for vm_i, vm_type in common.VM_TYPES.items():
vm_used_bdf = []
# bdf 00:00.0 is reserved for pci host bridge of any type of VM
bdf_tuple = BusDevFunc.from_str("00:00.0")
vm_used_bdf.append(bdf_tuple)
# Skip this vm if there is no any pci device and virtual device
if not scenario_cfg_lib.get_pci_dev_num_per_vm()[vm_i] and \
scenario_cfg_lib.VM_DB[vm_type]['load_type'] != "SOS_VM":
continue
if not scenario_cfg_lib.get_pci_dev_num_per_vm()[vm_i] and \
scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "SOS_VM":
print("", file=config)
print("struct acrn_vm_pci_dev_config " +
"sos_pci_devs[CONFIG_MAX_PCI_DEV_NUM];", file=config)
continue
pci_cnt = 1
# Insert device structure and bracket
print("", file=config)
if scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "SOS_VM":
print("struct acrn_vm_pci_dev_config " +
"sos_pci_devs[CONFIG_MAX_PCI_DEV_NUM] = {", file=config)
else:
print("struct acrn_vm_pci_dev_config " +
"vm{}_pci_devs[VM{}_CONFIG_PCI_DEV_NUM] = {{".format(vm_i, vm_i), file=config)
# If a pre-launched vm has either passthrough pci devices or ivshmem devices, hostbridge is needed
if scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "PRE_LAUNCHED_VM":
pciHostbridge = False
# Check if there is a passtrhough pci devices
pci_bdf_devs_list = vm_info.cfg_pci.pci_devs[vm_i]
if pci_bdf_devs_list:
pciHostbridge = True
# Check if the ivshmem is enabled
if vm_info.shmem.shmem_enabled == 'y' and vm_i in vm_info.shmem.shmem_regions \
and len(vm_info.shmem.shmem_regions[vm_i]) > 0:
pciHostbridge = True
# Check if there is pci vuart is enabled
if pci_vuarts_num[vm_i] > 0:
pciHostbridge = True
if pciHostbridge:
print("\t{", file=config)
print("\t\t.emu_type = {},".format(PCI_DEV_TYPE[0]), file=config)
print("\t\t.vbdf.bits = {.b = 0x00U, .d = 0x00U, .f = 0x00U},", file=config)
print("\t\t.vdev_ops = &vhostbridge_ops,", file=config)
print("\t},", file=config)
# Insert passtrough devices data
if vm_i in vm_info.cfg_pci.pci_devs.keys():
pci_bdf_devs_list = vm_info.cfg_pci.pci_devs[vm_i]
if pci_bdf_devs_list:
for pci_bdf_dev in pci_bdf_devs_list:
if not pci_bdf_dev:
continue
bus = int(pci_bdf_dev.split(':')[0], 16)
dev = int(pci_bdf_dev.split(':')[1].split('.')[0], 16)
fun = int(pci_bdf_dev.split('.')[1], 16)
print("\t{", file=config)
print("\t\t.emu_type = {},".format(PCI_DEV_TYPE[1]), file=config)
print("\t\t.vbdf.bits = {{.b = 0x00U, .d = 0x{0:02x}U, .f = 0x00U}},".format(pci_cnt), file=config)
for bdf, bar_attr in board_cfg_lib.PCI_DEV_BAR_DESC.pci_dev_dic.items():
if bdf == pci_bdf_dev:
print("\t\tPTDEV({}),".format(board_cfg_lib.PCI_DEV_BAR_DESC.pci_dev_dic[bdf].name_w_i_cnt), file=config)
else:
continue
print("\t},", file=config)
bdf_tuple = BusDevFunc(0,pci_cnt,0)
vm_used_bdf.append(bdf_tuple)
pci_cnt += 1
# Insert ivshmem information
if vm_info.shmem.shmem_enabled == 'y' and vm_i in vm_info.shmem.shmem_regions \
and len(vm_info.shmem.shmem_regions[vm_i]) > 0:
raw_shm_list = vm_info.shmem.shmem_regions[vm_i]
index = 0
last_bdf = BusDevFunc(bus=0x00, dev=0x00, func=0x0)
for shm in raw_shm_list:
shm_splited = shm.split(',')
print("\t{", file=config)
print("\t\t.emu_type = {},".format(PCI_DEV_TYPE[0]), file=config)
if scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "SOS_VM":
free_bdf = find_unused_bdf(sos_used_bdf, "ivshmem", last_bdf)
last_bdf = free_bdf
print("\t\t.vbdf.bits = {{.b = 0x00U, .d = 0x{:02x}U, .f = 0x{:02x}U}}," \
.format(free_bdf.dev,free_bdf.func), file=config)
sos_used_bdf.append(free_bdf)
elif scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "PRE_LAUNCHED_VM":
print("\t\t.vbdf.bits = {{.b = 0x00U, .d = 0x{0:02x}U, .f = 0x00U}},".format(pci_cnt), file=config)
bdf_tuple = BusDevFunc(0,pci_cnt,0)
vm_used_bdf.append(bdf_tuple)
elif scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "POST_LAUNCHED_VM":
print("\t\t.vbdf.value = UNASSIGNED_VBDF,", file=config)
print("\t\t.vdev_ops = &vpci_ivshmem_ops,", file=config)
for shm_name,_ in board_cfg_lib.PCI_DEV_BAR_DESC.shm_bar_dic.items():
region = shm_name[:shm_name.find('_')]
shm_name = shm_name[shm_name.find('_') + 1:]
if shm_name == shm_splited[0].strip():
if scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "PRE_LAUNCHED_VM":
print("\t\t.shm_region_name = IVSHMEM_SHM_REGION_{},".format(region), file=config)
print("\t\tIVSHMEM_DEVICE_{}_VBAR".format(index), file=config)
elif scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "SOS_VM":
print("\t\t.shm_region_name = IVSHMEM_SHM_REGION_{},".format(region), file=config)
print("\t\tSOS_IVSHMEM_DEVICE_{}_VBAR".format(index), file=config)
else:
print("\t\t.shm_region_name = IVSHMEM_SHM_REGION_{}".format(region), file=config)
pci_cnt += 1
index += 1
print("\t},", file=config)
if vm_i in vuarts.keys():
# get legacy vuart information
vuart0_setting = common.get_vuart_info_id(common.SCENARIO_INFO_FILE, 0)
vuart1_setting = common.get_vuart_info_id(common.SCENARIO_INFO_FILE, 1)
last_bdf = BusDevFunc(bus=0x00, dev=0x00, func=0x0)
for vuart_id in vuarts[vm_i].keys():
if vuarts[vm_i][vuart_id]['base'] == "INVALID_PCI_BASE":
continue
# skip pci vuart 0 for post-launched vm
if vuart_id == 0 and scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "POST_LAUNCHED_VM":
continue
# Skip pci vuart 0 if the legacy vuart 0 is enabled
if vuart_id == 0 and vm_i in vuart0_setting and vuart0_setting[vm_i]['base'] != "INVALID_COM_BASE":
continue
# Skip pci vuart 1 if the legacy vuart 1 is enabled
if vuart_id == 1 and vm_i in vuart1_setting and vuart1_setting[vm_i]['base'] != "INVALID_COM_BASE":
continue
print("\t{", file=config)
print("\t\t.vuart_idx = {:1d},".format(vuart_id), file=config)
print("\t\t.emu_type = {},".format(PCI_DEV_TYPE[0]), file=config)
print("\t\t.vdev_ops = &vmcs9900_ops,", file=config)
if vuart_id != 0 and scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "POST_LAUNCHED_VM":
print("\t\t.vbar_base[0] = INVALID_PCI_BASE,", file=config)
print("\t\t.vbdf.value = UNASSIGNED_VBDF,", file=config)
if scenario_cfg_lib.VM_DB[vm_type]['load_type'] != "POST_LAUNCHED_VM":
print("\t\tVM{:1d}_VUART_{:1d}_VBAR,".format(vm_i, vuart_id), file=config)
if scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "PRE_LAUNCHED_VM":
free_bdf = find_unused_bdf(vm_used_bdf, "vuart", last_bdf)
vm_used_bdf.append(free_bdf)
elif scenario_cfg_lib.VM_DB[vm_type]['load_type'] == "SOS_VM":
free_bdf = find_unused_bdf(sos_used_bdf, "vuart", last_bdf)
sos_used_bdf.append(free_bdf)
print("\t\t.vbdf.bits = {{.b = 0x00U, .d = 0x{:02x}U, .f = 0x00U}},".format(free_bdf.dev,free_bdf.func), file=config)
if vuart_id != 0:
print("\t\t.t_vuart.vm_id = {},".format(vuarts[vm_i][vuart_id]['target_vm_id']), file=config)
print("\t\t.t_vuart.vuart_id = {},".format(vuarts[vm_i][vuart_id]['target_uart_id']), file=config)
pci_cnt += 1
print("\t},", file=config)
# Insert the end bracket of the pci_dev.c file
print("};", file=config)