Merge "Improve Intel FPGA driver"

This commit is contained in:
Zuul 2019-03-08 06:27:32 +00:00 committed by Gerrit Code Review
commit 54ff02c00f
6 changed files with 153 additions and 149 deletions

View File

@ -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

View File

@ -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)
}

View File

@ -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),

View File

@ -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)

View File

@ -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):

View File

@ -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")