# Copyright (C) 2019 Intel Corporation. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # import collections import board_cfg_lib import common PCI_HEADER = r""" #ifndef PCI_DEVICES_H_ #define PCI_DEVICES_H_ """ PCI_END_HEADER = r""" #endif /* PCI_DEVICES_H_ */""" HI_MMIO_OFFSET = 0 class Bar_Mem: def __init__(self): self.addr = 0 self.remapped = False class Bar_Attr: def __init__(self): self.name = 0 self.remappable = True class Pci_Dev_Bar_Desc: def __init__(self): self.pci_dev_dic = {} self.pci_bar_dic = {} PCI_DEV_BAR_DESC = Pci_Dev_Bar_Desc() def get_value_after_str(line, key): """ Get the value after cstate string """ idx = 0 line_in_list = line.split() for idx_key, val in enumerate(line_in_list): if val == key: idx = idx_key break return line_in_list[idx + 1] def check_bar_remappable(line): #TODO: check device BAR remappable per ACPI table return True def get_size(line): # get size string from format, Region n: Memory at x ... [size=NK] size_str = line.split()[-1].strip(']').split('=')[1] if 'G' in size_str: size = int(size_str.strip('G')) * common.SIZE_G elif 'M' in size_str: size = int(size_str.strip('M')) * common.SIZE_M elif 'K' in size_str: size = int(size_str.strip('K')) * common.SIZE_K else: size = int(size_str) return size # round up the running bar_addr to the size of the incoming bar "line" def remap_bar_addr_to_high(bar_addr, line): """Generate vbar address""" global HI_MMIO_OFFSET size = get_size(line) cur_addr = common.round_up(bar_addr, size) HI_MMIO_OFFSET = cur_addr + size return cur_addr def parser_pci(): """ Parse PCI lines """ cur_bdf = 0 prev_bdf = 0 tmp_bar_dic = {} bar_addr = bar_num = '0' cal_sub_pci_name = [] pci_lines = board_cfg_lib.get_info( common.BOARD_INFO_FILE, "", "") for line in pci_lines: tmp_bar_mem = Bar_Mem() # get pci bar information into PCI_DEV_BAR_DESC if "Region" in line and "Memory at" in line: #ignore memory region from SR-IOV capabilities if "size=" not in line: continue bar_addr = int(get_value_after_str(line, "at"), 16) bar_num = line.split()[1].strip(':') if bar_addr >= common.SIZE_4G or bar_addr < common.SIZE_2G: if not tmp_bar_attr.remappable: continue bar_addr = remap_bar_addr_to_high(HI_MMIO_OFFSET, line) tmp_bar_mem.remapped = True tmp_bar_mem.addr = hex(bar_addr) tmp_bar_dic[int(bar_num)] = tmp_bar_mem else: tmp_bar_attr = Bar_Attr() prev_bdf = cur_bdf pci_bdf = line.split()[0] tmp_bar_attr.name = " ".join(line.split(':')[1].split()[1:]) # remove '[*]' in pci subname if '[' in tmp_bar_attr.name: tmp_bar_attr.name = tmp_bar_attr.name.rsplit('[', 1)[0] cal_sub_pci_name.append(tmp_bar_attr.name) tmp_bar_attr.remappable = check_bar_remappable(line) PCI_DEV_BAR_DESC.pci_dev_dic[pci_bdf] = tmp_bar_attr cur_bdf = pci_bdf if not prev_bdf: prev_bdf = cur_bdf if tmp_bar_dic and cur_bdf != prev_bdf: PCI_DEV_BAR_DESC.pci_bar_dic[prev_bdf] = tmp_bar_dic # clear the tmp_bar_dic before store the next dic tmp_bar_dic = {} # output all the pci device list to pci_device.h sub_name_count = collections.Counter(cal_sub_pci_name) if tmp_bar_dic: PCI_DEV_BAR_DESC.pci_bar_dic[cur_bdf] = tmp_bar_dic return sub_name_count def write_pbdf(i_cnt, bdf, bar_attr, config): """ Parser and generate pbdf :param i_cnt: the number of pci devices have the same PCI sub class name :param bdf: it is a string what contains BDF :param bar_attr: it is a class, contains PIC bar attribute :param config: it is a file pointer of pci information for writing to """ # if there is only one host bridge, then will discard the index of suffix 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) bus = int(bdf.split(':')[0], 16) dev = int(bdf.split(':')[1].split('.')[0], 16) fun = int(bdf.split('.')[1], 16) print("#define %-32s" % tmp_sub_name, end="", file=config) print(" .pbdf.bits = {{.b = 0x{:02X}U, .d = 0x{:02X}U, .f = 0x{:02X}U}}".format( bus, dev, fun), end="", file=config) if not bar_attr.remappable: align = ' ' * 48 print("\n{}/* TODO: add {} 64bit BAR support */".format(align, tmp_sub_name), file=config) return def write_vbar(i_cnt, bdf, pci_bar_dic, bar_attr, config): """ Parser and generate vbar :param i_cnt: the number of pci devices have the same PCI sub class name :param bdf: it is a string what contains BDF :param pci_bar_dic: it is a dictionary of pci vbar for those BDF :param bar_attr: it is a class, contains PIC bar attribute :param config: it is a file pointer of pci information for writing to """ tail = 0 align = ' ' * 48 ptdev_mmio_str = '' tmp_sub_name = common.undline_name(bar_attr.name) + "_" + str(i_cnt) if bdf in pci_bar_dic.keys(): bar_list = list(pci_bar_dic[bdf].keys()) bar_len = len(bar_list) bar_num = 0 for bar_i in bar_list: if not bar_attr.remappable: return if tail == 0: print(", \\", file=config) tail += 1 bar_num += 1 bar_val = pci_bar_dic[bdf][bar_i].addr if pci_bar_dic[bdf][bar_i].remapped: ptdev_mmio_str = 'PTDEV_HI_MMIO_START + ' if bar_num == bar_len: print("{}.vbar_base[{}] = {}{}UL".format(align, bar_i, ptdev_mmio_str, bar_val), file=config) else: print("{}.vbar_base[{}] = {}{}UL, \\".format( align, bar_i, ptdev_mmio_str, bar_val), file=config) else: print("", file=config) def generate_file(config): """ Get PCI device and generate pci_devices.h :param config: it is a file pointer of pci information for writing to """ # write the license into pci print("{0}".format(board_cfg_lib.HEADER_LICENSE), file=config) # add bios and base board info board_cfg_lib.handle_bios_info(config) # write the header into pci print("{0}".format(PCI_HEADER), file=config) sub_name_count = parser_pci() print("#define %-32s" % "PTDEV_HI_MMIO_SIZE", " {}UL".format(hex(HI_MMIO_OFFSET)), file=config) compared_bdf = [] for cnt_sub_name in sub_name_count.keys(): i_cnt = 0 for bdf, bar_attr in 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 print("",file=config) write_pbdf(i_cnt, bdf, bar_attr, config) write_vbar(i_cnt, bdf, PCI_DEV_BAR_DESC.pci_bar_dic, bar_attr, config) i_cnt += 1 # write the end to the pci devices print("{0}".format(PCI_END_HEADER), file=config)