Merge "Improve Intel FPGA driver"
This commit is contained in:
commit
54ff02c00f
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
|
@ -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):
|
|
@ -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")
|
Loading…
Reference in New Issue