From 0bc8ca656288a49bd217f6a1515ba68ff767b737 Mon Sep 17 00:00:00 2001 From: Xinran WANG Date: Tue, 7 May 2019 18:19:22 +0800 Subject: [PATCH] Improve Intel sysinfo based FPGA driver Each driver should report the resource class and traits to Cyborg agent in order to let agent pass them to conductor, then conductor could call placment to update them. In FPGA case, driver should discover RC as "CUSTOM_ACCELERATOR_FPGA" and also discover the function id, region type if exist, as TRAITS. The placement report work depends on this patch. We should also improve the OPEA in the future. Change-Id: I4a679a7b93de62dbca25e293f7c2e7e71ffad2a5 --- .../accelerator/drivers/fpga/intel/sysinfo.py | 69 +++++++++++++++++-- cyborg/agent/rc_fields.py | 1 + 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/cyborg/accelerator/drivers/fpga/intel/sysinfo.py b/cyborg/accelerator/drivers/fpga/intel/sysinfo.py index 56ffc34a..b64b838b 100644 --- a/cyborg/accelerator/drivers/fpga/intel/sysinfo.py +++ b/cyborg/accelerator/drivers/fpga/intel/sysinfo.py @@ -22,9 +22,11 @@ Cyborg Intel FPGA driver implementation. import glob import os import re -from cyborg import objects +from oslo_serialization import jsonutils + +from cyborg.agent import rc_fields from cyborg.objects.driver_objects import driver_deployable, driver_device,\ - driver_attach_handle, driver_controlpath_id + driver_attach_handle, driver_controlpath_id, driver_attribute from cyborg.common import constants SYS_FPGA = "/sys/class/fpga" @@ -36,10 +38,17 @@ BDF_PATTERN = re.compile( DEVICE_FILE_MAP = {"vendor": "vendor", - "device": "model"} + "device": "product_id"} DEVICE_FILE_HANDLER = {} DEVICE_EXPOSED = ["vendor", "device"] +RC_FPGA = rc_fields.ResourceClass.normalize_name( + rc_fields.ResourceClass.FPGA) + +RESOURCES = { + "fpga": RC_FPGA +} + def all_fpgas(): # glob.glob1("/sys/class/fpga", "*") @@ -111,6 +120,26 @@ def get_pf_bdf(bdf): return bdf +def get_afu_ids(name): + ids = [] + for path in glob.glob(os.path.join( + SYS_FPGA, name, "intel-fpga-port.*", "afu_id")): + with open(path) as f: + first_line = f.readline() + ids.append(first_line.split('\n', 1)[0]) + return ids + + +def get_traits(name, product_id): + # "region_id" not support at present, "CUSTOM_FPGA_REGION_INTEL_UUID" + # "CUSTOM_PROGRAMMABLE" not support at present + traits = ["CUSTOM_FPGA_INTEL"] + for i in get_afu_ids(name): + l = "CUSTOM_FPGA_INTEL_FUNCTION_" + i.upper() + traits.append(l) + return {"traits": traits} + + def fpga_device(path): infos = {} @@ -142,13 +171,18 @@ def fpga_tree(): "name": name} d_info = fpga_device(dpath) fpga.update(d_info) + traits = get_traits(fpga["name"], fpga["product_id"]) + fpga.update(traits) + fpga["rc"] = RESOURCES["fpga"] return fpga devs = [] pf_has_vf = all_pfs_have_vf() for pf in all_pf_fpgas(): fpga = gen_fpga_infos(pf, False) if pf in pf_has_vf: + # Currently only one region supported. fpga["regions"] = [] + # All VFs here belong to one same region. vfs = all_vfs_in_pf_fpgas(pf) for vf in vfs: vf_fpga = gen_fpga_infos(vf, True) @@ -160,7 +194,11 @@ def fpga_tree(): def _generate_driver_device(fpga, pf_has_vf): driver_device_obj = driver_device.DriverDevice() driver_device_obj.vendor = fpga["vendor"] - driver_device_obj.model = fpga["model"] + driver_device_obj.model = fpga.get('model', "miss_model_info") + driver_device_obj.vendor_board_info = fpga.get('vendor_board_info', + "miss_vb_info") + std_board_info = {'product_id': fpga.get('product_id', None)} + driver_device_obj.std_board_info = jsonutils.dumps(std_board_info) driver_device_obj.type = fpga["type"] driver_device_obj.controlpath_id = _generate_controlpath_id(fpga) driver_device_obj.deployable_list = _generate_dep_list(fpga, pf_has_vf) @@ -177,6 +215,7 @@ def _generate_controlpath_id(fpga): def _generate_dep_list(fpga, pf_has_vf): dep_list = [] driver_dep = driver_deployable.DriverDeployable() + driver_dep.attribute_list = _generate_attribute_list(fpga) driver_dep.attach_handle_list = [] # pf without sriov enabled. if not pf_has_vf: @@ -189,11 +228,11 @@ def _generate_dep_list(fpga, pf_has_vf): else: driver_dep.num_accelerators = len(fpga["regions"]) for vf in fpga["regions"]: + # Only vfs in regions can be attach, no pf. driver_dep.attach_handle_list.append( _generate_attach_handle(vf, False)) driver_dep.name = vf["name"] - dep_list.append(driver_dep) - return dep_list + return [driver_dep] def _generate_attach_handle(fpga, pf_has_vf): @@ -202,3 +241,21 @@ def _generate_attach_handle(fpga, pf_has_vf): driver_ah.attach_info = fpga["devices"] driver_ah.in_use = False return driver_ah + + +def _generate_attribute_list(fpga): + attr_list = [] + for k, v in fpga.items(): + if k == "rc": + driver_attr = driver_attribute.DriverAttribute() + driver_attr.key = k + driver_attr.value = fpga.get(k, None) + attr_list.append(driver_attr) + if k == "traits": + values = fpga.get(k, None) + for val in values: + driver_attr = driver_attribute.DriverAttribute() + driver_attr.key = "trait" + str(values.index(val)) + driver_attr.value = val + attr_list.append(driver_attr) + return attr_list diff --git a/cyborg/agent/rc_fields.py b/cyborg/agent/rc_fields.py index add6c76a..44e39b7a 100644 --- a/cyborg/agent/rc_fields.py +++ b/cyborg/agent/rc_fields.py @@ -41,6 +41,7 @@ class ResourceClass(fields.StringField): IPV4_ADDRESS = 'IPV4_ADDRESS' VGPU = 'VGPU' VGPU_DISPLAY_HEAD = 'VGPU_DISPLAY_HEAD' + FPGA = 'ACCELERATOR_FPGA' # The ordering here is relevant. If you must add a value, only # append.