diff --git a/cyborg/accelerator/drivers/fpga/intel/sysinfo.py b/cyborg/accelerator/drivers/fpga/intel/sysinfo.py index 6b8e01a3..656ad0b3 100644 --- a/cyborg/accelerator/drivers/fpga/intel/sysinfo.py +++ b/cyborg/accelerator/drivers/fpga/intel/sysinfo.py @@ -22,7 +22,10 @@ Cyborg Intel FPGA driver implementation. import glob import os import re - +from cyborg import objects +from cyborg.objects.driver_objects import driver_deployable, driver_device,\ + driver_attach_handle, driver_controlpath_id +from cyborg.common import constants SYS_FPGA = "/sys/class/fpga" DEVICE = "device" @@ -32,11 +35,10 @@ BDF_PATTERN = re.compile( "^[a-fA-F\d]{4}:[a-fA-F\d]{2}:[a-fA-F\d]{2}\.[a-fA-F\d]$") -DEVICE_FILE_MAP = {"vendor": "vendor_id", - "device": "product_id", - "sriov_numvfs": "pr_num"} +DEVICE_FILE_MAP = {"vendor": "vendor", + "device": "model"} DEVICE_FILE_HANDLER = {} -DEVICE_EXPOSED = ["vendor", "device", "sriov_numvfs"] +DEVICE_EXPOSED = ["vendor", "device"] def all_fpgas(): @@ -49,7 +51,7 @@ def all_vf_fpgas(): glob.glob(os.path.join(SYS_FPGA, "*/device/physfn"))] -def all_pure_pf_fpgas(): +def all_pfs_have_vf(): return [dev.rsplit("/", 2)[0] for dev in glob.glob(os.path.join(SYS_FPGA, "*/device/virtfn0"))] @@ -131,33 +133,72 @@ def fpga_device(path): def fpga_tree(): - def gen_fpga_infos(path, vf=True): name = os.path.basename(path) dpath = os.path.realpath(os.path.join(path, DEVICE)) bdf = os.path.basename(dpath) - func = "vf" if vf else "pf" - pf_bdf = os.path.basename( - os.path.realpath(os.path.join(dpath, PF))) if vf else "" - fpga = {"path": path, "function": func, - "devices": bdf, "assignable": True, - "parent_devices": pf_bdf, - "name": name, - "interface_type": "pci"} + fpga = {"type": constants.DEVICE_FPGA, + "devices": bdf, + "name": name} d_info = fpga_device(dpath) fpga.update(d_info) return fpga - devs = [] - pure_pfs = all_pure_pf_fpgas() + pf_has_vf = all_pfs_have_vf() for pf in all_pf_fpgas(): fpga = gen_fpga_infos(pf, False) - if pf in pure_pfs: - fpga["assignable"] = False + if pf in pf_has_vf: fpga["regions"] = [] vfs = all_vfs_in_pf_fpgas(pf) for vf in vfs: vf_fpga = gen_fpga_infos(vf, True) fpga["regions"].append(vf_fpga) - devs.append(fpga) + devs.append(_generate_driver_device(fpga, pf in pf_has_vf)) return devs + + +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.type = fpga["type"] + driver_device_obj.controlpath_id = _generate_controlpath_id(fpga) + driver_device_obj.deployable_list = _generate_dep_list(fpga, pf_has_vf) + return driver_device_obj + + +def _generate_controlpath_id(fpga): + driver_cpid = driver_controlpath_id.DriverControlPathID() + driver_cpid.cpid_type = "pci" + driver_cpid.cpid_info = fpga["devices"] + return driver_cpid + + +def _generate_dep_list(fpga, pf_has_vf): + dep_list = [] + driver_dep = driver_deployable.DriverDeployable() + driver_dep.attach_handle_list = [] + # pf without sriov enabled. + if not pf_has_vf: + driver_dep.num_accelerators = 1 + driver_dep.attach_handle_list = \ + [_generate_attach_handle(fpga, pf_has_vf)] + driver_dep.name = fpga["name"] + # pf with sriov enabled, may have several regions and several vfs. + # For now, there is only region, this maybe improve in next release. + else: + driver_dep.num_accelerators = len(fpga["regions"]) + for vf in fpga["regions"]: + driver_dep.attach_handle_list.append( + _generate_attach_handle(vf, False)) + driver_dep.name = vf["name"] + dep_list.append(driver_dep) + return dep_list + + +def _generate_attach_handle(fpga, pf_has_vf): + driver_ah = driver_attach_handle.DriverAttachHandle() + driver_ah.attach_type = "pci" + driver_ah.attach_info = fpga["devices"] + driver_ah.in_use = False + return driver_ah diff --git a/cyborg/objects/driver_objects/driver_attach_handle.py b/cyborg/objects/driver_objects/driver_attach_handle.py index 196b59b4..4bd021a4 100644 --- a/cyborg/objects/driver_objects/driver_attach_handle.py +++ b/cyborg/objects/driver_objects/driver_attach_handle.py @@ -28,4 +28,6 @@ class DriverAttachHandle(base.DriverObjectBase, 'attach_type': object_fields.StringField(nullable=False), # PCI BDF or mediated device ID... 'attach_info': object_fields.StringField(nullable=False), + # The status of attach_handle, is in use or not. + 'in_use': object_fields.BooleanField(nullable=False, default=False) } diff --git a/cyborg/objects/driver_objects/driver_deployable.py b/cyborg/objects/driver_objects/driver_deployable.py index 4d1842e6..3c621135 100644 --- a/cyborg/objects/driver_objects/driver_deployable.py +++ b/cyborg/objects/driver_objects/driver_deployable.py @@ -28,6 +28,7 @@ class DriverDeployable(base.DriverObjectBase, VERSION = '1.0' fields = { + 'name': object_fields.StringField(nullable=False), 'num_accelerators': object_fields.IntegerField(nullable=False), 'attribute_list': object_fields.ListOfObjectsField( 'DriverAttribute', default=[], nullable=True), diff --git a/cyborg/tests/unit/accelerator/drivers/fpga/base.py b/cyborg/tests/unit/accelerator/drivers/fpga/base.py deleted file mode 100644 index 0bd6ab69..00000000 --- a/cyborg/tests/unit/accelerator/drivers/fpga/base.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2018 Intel, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -import os -import subprocess - -import fixtures - -from cyborg.accelerator.drivers.fpga.base import FPGADriver -from cyborg.accelerator.drivers.fpga.intel import sysinfo -from cyborg.tests import base -from cyborg.tests.unit.accelerator.drivers.fpga.intel import prepare_test_data - - -class TestFPGADriver(base.TestCase): - - def setUp(self): - super(TestFPGADriver, self).setUp() - self.syspath = sysinfo.SYS_FPGA - sysinfo.SYS_FPGA = "/sys/class/fpga" - tmp_sys_dir = self.useFixture(fixtures.TempDir()) - prepare_test_data.create_fake_sysfs(tmp_sys_dir.path) - sysinfo.SYS_FPGA = os.path.join( - tmp_sys_dir.path, sysinfo.SYS_FPGA.split("/", 1)[-1]) - - def tearDown(self): - super(TestFPGADriver, self).tearDown() - sysinfo.SYS_FPGA = self.syspath - - def test_create(self): - FPGADriver.create("intel") - self.assertRaises(LookupError, FPGADriver.create, "xilinx") - - def test_discover(self): - d = FPGADriver() - self.assertRaises(NotImplementedError, d.discover) - - def test_program(self): - d = FPGADriver() - self.assertRaises(NotImplementedError, d.program, "path", "image") - - def test_intel_discover(self): - expect = [{'function': 'pf', 'assignable': False, 'pr_num': '1', - 'vendor_id': '0x8086', 'devices': '0000:5e:00.0', - 'regions': [{ - 'function': 'vf', 'assignable': True, - 'product_id': '0xbcc1', - 'name': 'intel-fpga-dev.2', - 'parent_devices': '0000:5e:00.0', - 'path': '%s/intel-fpga-dev.2' % sysinfo.SYS_FPGA, - 'vendor_id': '0x8086', - 'devices': '0000:5e:00.1'}], - 'name': 'intel-fpga-dev.0', - 'parent_devices': '', - 'path': '%s/intel-fpga-dev.0' % sysinfo.SYS_FPGA, - 'product_id': '0xbcc0'}, - {'function': 'pf', 'assignable': True, 'pr_num': '0', - 'vendor_id': '0x8086', 'devices': '0000:be:00.0', - 'name': 'intel-fpga-dev.1', - 'parent_devices': '', - 'path': '%s/intel-fpga-dev.1' % sysinfo.SYS_FPGA, - 'product_id': '0xbcc0'}] - expect.sort() - - intel = FPGADriver.create("intel") - fpgas = intel.discover() - fpgas.sort() - self.assertEqual(2, len(fpgas)) - self.assertEqual(fpgas, expect) - - @mock.patch.object(subprocess, 'Popen', autospec=True) - def test_intel_program(self, mock_popen): - - class p(object): - returncode = 0 - - def wait(self): - pass - - b = "0x5e" - d = "0x00" - f = "0x0" - expect_cmd = ['sudo', '/usr/bin/fpgaconf', '-b', b, - '-d', d, '-f', f, '/path/image'] - mock_popen.return_value = p() - intel = FPGADriver.create("intel") - # program VF - intel.program("0000:5e:00.1", "/path/image") - mock_popen.assert_called_with(expect_cmd, stdout=subprocess.PIPE) - - # program PF - intel.program("0000:5e:00.0", "/path/image") - mock_popen.assert_called_with(expect_cmd, stdout=subprocess.PIPE) diff --git a/cyborg/tests/unit/accelerator/drivers/fpga/intel/driver.py b/cyborg/tests/unit/accelerator/drivers/fpga/intel/test_driver.py similarity index 50% rename from cyborg/tests/unit/accelerator/drivers/fpga/intel/driver.py rename to cyborg/tests/unit/accelerator/drivers/fpga/intel/test_driver.py index 6719d7ca..756176dc 100644 --- a/cyborg/tests/unit/accelerator/drivers/fpga/intel/driver.py +++ b/cyborg/tests/unit/accelerator/drivers/fpga/intel/test_driver.py @@ -40,33 +40,60 @@ class TestIntelFPGADriver(base.TestCase): sysinfo.SYS_FPGA = self.syspath def test_discover(self): - expect = [{'function': 'pf', 'assignable': False, 'pr_num': '1', - 'vendor_id': '0x8086', 'devices': '0000:5e:00.0', - 'regions': [{ - 'function': 'vf', 'assignable': True, - 'product_id': '0xbcc1', - 'name': 'intel-fpga-dev.2', - 'parent_devices': '0000:5e:00.0', - 'path': '%s/intel-fpga-dev.2' % sysinfo.SYS_FPGA, - 'vendor_id': '0x8086', - 'devices': '0000:5e:00.1'}], - 'name': 'intel-fpga-dev.0', - 'parent_devices': '', - 'path': '%s/intel-fpga-dev.0' % sysinfo.SYS_FPGA, - 'product_id': '0xbcc0'}, - {'function': 'pf', 'assignable': True, 'pr_num': '0', - 'vendor_id': '0x8086', 'devices': '0000:be:00.0', - 'parent_devices': '', - 'name': 'intel-fpga-dev.1', - 'path': '%s/intel-fpga-dev.1' % sysinfo.SYS_FPGA, - 'product_id': '0xbcc0'}] - expect.sort() - + attach_handle_list = [ + [ + {'attach_type': 'pci', + 'attach_info': '0000:be:00.0', + 'in_use': False} + ], + [ + {'attach_type': 'pci', + 'attach_info': '0000:5e:00.1', + 'in_use': False} + ] + ] + expected = [{'vendor': '0x8086', + 'type': 'FPGA', + 'model': '0xbcc0', + 'deployable_list': + [ + {'num_accelerators': 1, + 'name': 'intel-fpga-dev.1', + 'attach_handle_list': attach_handle_list[0] + }, + ], + 'controlpath_id': + {'cpid_info': '0000:be:00.0', + 'cpid_type': 'pci'}}, + {'vendor': '0x8086', + 'type': 'FPGA', + 'model': '0xbcc0', + 'deployable_list': + [ + {'num_accelerators': 1, + 'name': 'intel-fpga-dev.2', + 'attach_handle_list': attach_handle_list[1] + }, + ], + 'controlpath_id': + {'cpid_info': '0000:5e:00.0', + 'cpid_type': 'pci'}}] intel = IntelFPGADriver() fpgas = intel.discover() - fpgas.sort() self.assertEqual(2, len(fpgas)) - self.assertEqual(fpgas, expect) + for i in range(len(fpgas)): + fpga_dict = fpgas[i].as_dict() + fpga_dep_list = fpga_dict['deployable_list'] + fpga_attach_handle_list = \ + fpga_dep_list[0].as_dict()['attach_handle_list'] + self.assertEqual(expected[i]['vendor'], fpga_dict['vendor']) + self.assertEqual(expected[i]['controlpath_id'], + fpga_dict['controlpath_id'].as_dict()) + self.assertEqual(expected[i]['deployable_list'][0] + ['num_accelerators'], + fpga_dep_list[0].as_dict()['num_accelerators']) + self.assertEqual(attach_handle_list[i][0], + fpga_attach_handle_list[0].as_dict()) @mock.patch.object(subprocess, 'Popen', autospec=True) def test_intel_program(self, mock_popen): diff --git a/cyborg/tests/unit/accelerator/drivers/fpga/test_base.py b/cyborg/tests/unit/accelerator/drivers/fpga/test_base.py new file mode 100644 index 00000000..85fb3884 --- /dev/null +++ b/cyborg/tests/unit/accelerator/drivers/fpga/test_base.py @@ -0,0 +1,38 @@ +# Copyright 2018 Intel, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock +import os +import subprocess + +import fixtures + +from cyborg.accelerator.drivers.fpga.base import FPGADriver +from cyborg.accelerator.drivers.fpga.intel import sysinfo +from cyborg.tests import base +from cyborg.tests.unit.accelerator.drivers.fpga.intel import prepare_test_data + + +class TestFPGADriver(base.TestCase): + def test_create(self): + FPGADriver.create("intel") + self.assertRaises(LookupError, FPGADriver.create, "xilinx") + + def test_discover(self): + d = FPGADriver() + self.assertRaises(NotImplementedError, d.discover) + + def test_program(self): + d = FPGADriver() + self.assertRaises(NotImplementedError, d.program, "path", "image")