|
Packit |
534379 |
// Copyright(c) 2017-2020, Intel Corporation
|
|
Packit |
534379 |
//
|
|
Packit |
534379 |
// Redistribution and use in source and binary forms, with or without
|
|
Packit |
534379 |
// modification, are permitted provided that the following conditions are met:
|
|
Packit |
534379 |
//
|
|
Packit |
534379 |
// * Redistributions of source code must retain the above copyright notice,
|
|
Packit |
534379 |
// this list of conditions and the following disclaimer.
|
|
Packit |
534379 |
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
Packit |
534379 |
// this list of conditions and the following disclaimer in the documentation
|
|
Packit |
534379 |
// and/or other materials provided with the distribution.
|
|
Packit |
534379 |
// * Neither the name of Intel Corporation nor the names of its contributors
|
|
Packit |
534379 |
// may be used to endorse or promote products derived from this software
|
|
Packit |
534379 |
// without specific prior written permission.
|
|
Packit |
534379 |
//
|
|
Packit |
534379 |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
534379 |
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
534379 |
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
534379 |
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
Packit |
534379 |
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
Packit |
534379 |
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
Packit |
534379 |
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
Packit |
534379 |
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
Packit |
534379 |
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit |
534379 |
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
Packit |
534379 |
// POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
534379 |
#include <config.h>
|
|
Packit |
534379 |
#endif // HAVE_CONFIG_H
|
|
Packit |
534379 |
|
|
Packit |
534379 |
#include <stdlib.h>
|
|
Packit |
534379 |
#include <string.h>
|
|
Packit |
534379 |
#include <errno.h>
|
|
Packit |
534379 |
#include <sys/types.h>
|
|
Packit |
534379 |
#include <sys/stat.h>
|
|
Packit |
534379 |
#include <dirent.h>
|
|
Packit |
534379 |
#include <fcntl.h>
|
|
Packit |
534379 |
#include <unistd.h>
|
|
Packit |
534379 |
|
|
Packit |
534379 |
#include "xfpga.h"
|
|
Packit |
534379 |
#include "common_int.h"
|
|
Packit |
534379 |
#include "error_int.h"
|
|
Packit |
534379 |
#include "props.h"
|
|
Packit |
534379 |
|
|
Packit |
534379 |
/* mutex to protect global data structures */
|
|
Packit |
534379 |
extern pthread_mutex_t global_lock;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
struct dev_list {
|
|
Packit |
534379 |
char sysfspath[SYSFS_PATH_MAX];
|
|
Packit |
534379 |
char devpath[DEV_PATH_MAX];
|
|
Packit |
534379 |
fpga_objtype objtype;
|
|
Packit |
534379 |
fpga_guid guid;
|
|
Packit |
534379 |
uint16_t segment;
|
|
Packit |
534379 |
uint8_t bus;
|
|
Packit |
534379 |
uint8_t device;
|
|
Packit |
534379 |
uint8_t function;
|
|
Packit |
534379 |
uint8_t socket_id;
|
|
Packit |
534379 |
uint16_t vendor_id;
|
|
Packit |
534379 |
uint16_t device_id;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
uint32_t fpga_num_slots;
|
|
Packit |
534379 |
uint64_t fpga_bitstream_id;
|
|
Packit |
534379 |
fpga_version fpga_bbs_version;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
fpga_accelerator_state accelerator_state;
|
|
Packit |
534379 |
uint32_t accelerator_num_mmios;
|
|
Packit |
534379 |
uint32_t accelerator_num_irqs;
|
|
Packit |
534379 |
struct dev_list *next;
|
|
Packit |
534379 |
struct dev_list *parent;
|
|
Packit |
534379 |
struct dev_list *fme;
|
|
Packit |
534379 |
};
|
|
Packit |
534379 |
|
|
Packit |
534379 |
STATIC bool matches_filter(const struct dev_list *attr, const fpga_properties filter)
|
|
Packit |
534379 |
{
|
|
Packit |
534379 |
struct _fpga_properties *_filter = (struct _fpga_properties *)filter;
|
|
Packit |
534379 |
bool res = true;
|
|
Packit |
534379 |
int err = 0;
|
|
Packit |
534379 |
char buffer[PATH_MAX] = {0};
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (pthread_mutex_lock(&_filter->lock)) {
|
|
Packit |
534379 |
OPAE_MSG("Failed to lock filter mutex");
|
|
Packit |
534379 |
return false;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_PARENT)) {
|
|
Packit |
534379 |
struct _fpga_token *_parent_tok =
|
|
Packit |
534379 |
(struct _fpga_token *)_filter->parent;
|
|
Packit |
534379 |
char spath[PATH_MAX] = {0};
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FPGA_ACCELERATOR != attr->objtype) {
|
|
Packit |
534379 |
res = false; // Only accelerator can have a parent
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (NULL == _parent_tok) {
|
|
Packit |
534379 |
res = false; // Reject search based on NULL parent token
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (sysfs_get_fme_path(attr->sysfspath, spath) != FPGA_OK) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
// sysfs_get_fme_path returns the real path
|
|
Packit |
534379 |
// compare that agains the realpath of the parent_tok
|
|
Packit |
534379 |
if (!realpath(_parent_tok->sysfspath, buffer)) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
if (strcmp(spath, buffer)) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_OBJTYPE)) {
|
|
Packit |
534379 |
if (_filter->objtype != attr->objtype) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_SEGMENT)) {
|
|
Packit |
534379 |
if (_filter->segment != attr->segment) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_BUS)) {
|
|
Packit |
534379 |
if (_filter->bus != attr->bus) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_DEVICE)) {
|
|
Packit |
534379 |
if (_filter->device != attr->device) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_FUNCTION)) {
|
|
Packit |
534379 |
if (_filter->function != attr->function) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_SOCKETID)) {
|
|
Packit |
534379 |
if (_filter->socket_id != attr->socket_id) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_GUID)) {
|
|
Packit |
534379 |
if (0 != memcmp(attr->guid, _filter->guid, sizeof(fpga_guid))) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_OBJECTID)) {
|
|
Packit |
534379 |
uint64_t objid;
|
|
Packit |
534379 |
fpga_result result;
|
|
Packit |
534379 |
result = sysfs_objectid_from_path(attr->sysfspath, &objid);
|
|
Packit |
534379 |
if (result != FPGA_OK || _filter->object_id != objid) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_VENDORID)) {
|
|
Packit |
534379 |
if (_filter->vendor_id != attr->vendor_id) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_DEVICEID)) {
|
|
Packit |
534379 |
if (_filter->device_id != attr->device_id) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_NUM_ERRORS)) {
|
|
Packit |
534379 |
uint32_t errors;
|
|
Packit |
534379 |
char errpath[SYSFS_PATH_MAX] = { 0, };
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (snprintf(errpath, sizeof(errpath),
|
|
Packit |
534379 |
"%s/errors", attr->sysfspath) < 0) {
|
|
Packit |
534379 |
OPAE_ERR("snprintf buffer overflow");
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
errors = count_error_files(errpath);
|
|
Packit |
534379 |
if (errors != _filter->num_errors) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_OBJTYPE)
|
|
Packit |
534379 |
&& (FPGA_DEVICE == _filter->objtype)) {
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_NUM_SLOTS)) {
|
|
Packit |
534379 |
if ((FPGA_DEVICE != attr->objtype)
|
|
Packit |
534379 |
|| (attr->fpga_num_slots
|
|
Packit |
534379 |
!= _filter->u.fpga.num_slots)) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_BBSID)) {
|
|
Packit |
534379 |
if ((FPGA_DEVICE != attr->objtype)
|
|
Packit |
534379 |
|| (attr->fpga_bitstream_id
|
|
Packit |
534379 |
!= _filter->u.fpga.bbs_id)) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_BBSVERSION)) {
|
|
Packit |
534379 |
if ((FPGA_DEVICE != attr->objtype)
|
|
Packit |
534379 |
|| (attr->fpga_bbs_version.major
|
|
Packit |
534379 |
!= _filter->u.fpga.bbs_version.major)
|
|
Packit |
534379 |
|| (attr->fpga_bbs_version.minor
|
|
Packit |
534379 |
!= _filter->u.fpga.bbs_version.minor)
|
|
Packit |
534379 |
|| (attr->fpga_bbs_version.patch
|
|
Packit |
534379 |
!= _filter->u.fpga.bbs_version.patch)) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
} else if (FIELD_VALID(_filter, FPGA_PROPERTY_OBJTYPE)
|
|
Packit |
534379 |
&& (FPGA_ACCELERATOR == _filter->objtype)) {
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_ACCELERATOR_STATE)) {
|
|
Packit |
534379 |
if ((FPGA_ACCELERATOR != attr->objtype)
|
|
Packit |
534379 |
|| (attr->accelerator_state
|
|
Packit |
534379 |
!= _filter->u.accelerator.state)) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_NUM_MMIO)) {
|
|
Packit |
534379 |
if ((FPGA_ACCELERATOR != attr->objtype)
|
|
Packit |
534379 |
|| (attr->accelerator_num_mmios
|
|
Packit |
534379 |
!= _filter->u.accelerator.num_mmio)) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_NUM_INTERRUPTS)) {
|
|
Packit |
534379 |
if ((FPGA_ACCELERATOR != attr->objtype)
|
|
Packit |
534379 |
|| (attr->accelerator_num_irqs
|
|
Packit |
534379 |
!= _filter->u.accelerator.num_interrupts)) {
|
|
Packit |
534379 |
res = false;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
out_unlock:
|
|
Packit |
534379 |
err = pthread_mutex_unlock(&_filter->lock);
|
|
Packit |
534379 |
if (err) {
|
|
Packit |
534379 |
OPAE_ERR("pthread_mutex_unlock() failed: %S", strerror(err));
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
return res;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
STATIC bool matches_filters(const struct dev_list *attr, const fpga_properties *filter,
|
|
Packit |
534379 |
uint32_t num_filter)
|
|
Packit |
534379 |
{
|
|
Packit |
534379 |
uint32_t i;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (!num_filter) // no filter == match everything
|
|
Packit |
534379 |
return true;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
for (i = 0; i < num_filter; ++i) {
|
|
Packit |
534379 |
if (matches_filter(attr, filter[i])) {
|
|
Packit |
534379 |
return true;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
return false;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
STATIC struct dev_list *add_dev(const char *sysfspath, const char *devpath,
|
|
Packit |
534379 |
struct dev_list *parent)
|
|
Packit |
534379 |
{
|
|
Packit |
534379 |
struct dev_list *pdev;
|
|
Packit |
534379 |
size_t len;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
pdev = (struct dev_list *)calloc(1, sizeof(*pdev));
|
|
Packit |
534379 |
if (NULL == pdev)
|
|
Packit |
534379 |
return NULL;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
len = strnlen(sysfspath, sizeof(pdev->sysfspath) - 1);
|
|
Packit |
534379 |
memcpy(pdev->sysfspath, sysfspath, len);
|
|
Packit |
534379 |
pdev->sysfspath[len] = '\0';
|
|
Packit |
534379 |
|
|
Packit |
534379 |
len = strnlen(devpath, sizeof(pdev->devpath) - 1);
|
|
Packit |
534379 |
memcpy(pdev->devpath, devpath, len);
|
|
Packit |
534379 |
pdev->devpath[len] = '\0';
|
|
Packit |
534379 |
|
|
Packit |
534379 |
pdev->next = parent->next;
|
|
Packit |
534379 |
parent->next = pdev;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
pdev->parent = parent;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
return pdev;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
STATIC fpga_result enum_fme(const char *sysfspath, const char *name,
|
|
Packit |
534379 |
struct dev_list *parent)
|
|
Packit |
534379 |
{
|
|
Packit |
534379 |
fpga_result result;
|
|
Packit |
534379 |
struct stat stats;
|
|
Packit |
534379 |
struct dev_list *pdev;
|
|
Packit |
534379 |
char dpath[DEV_PATH_MAX];
|
|
Packit |
534379 |
int resval = 0;
|
|
Packit |
534379 |
uint64_t value = 0;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Make sure it's a directory.
|
|
Packit |
534379 |
if (stat(sysfspath, &stats) != 0) {
|
|
Packit |
534379 |
OPAE_MSG("stat failed: %s", strerror(errno));
|
|
Packit |
534379 |
return FPGA_NOT_FOUND;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (!S_ISDIR(stats.st_mode))
|
|
Packit |
534379 |
return FPGA_OK;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
snprintf(dpath, sizeof(dpath),
|
|
Packit |
534379 |
FPGA_DEV_PATH "/%s", name);
|
|
Packit |
534379 |
|
|
Packit |
534379 |
pdev = add_dev(sysfspath, dpath, parent);
|
|
Packit |
534379 |
if (!pdev) {
|
|
Packit |
534379 |
OPAE_MSG("Failed to allocate device");
|
|
Packit |
534379 |
return FPGA_NO_MEMORY;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
pdev->objtype = FPGA_DEVICE;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
pdev->segment = parent->segment;
|
|
Packit |
534379 |
pdev->bus = parent->bus;
|
|
Packit |
534379 |
pdev->device = parent->device;
|
|
Packit |
534379 |
pdev->function = parent->function;
|
|
Packit |
534379 |
pdev->vendor_id = parent->vendor_id;
|
|
Packit |
534379 |
pdev->device_id = parent->device_id;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Discover the FME GUID from sysfs (pr/interface_id)
|
|
Packit |
534379 |
result = sysfs_get_fme_pr_interface_id(sysfspath, pdev->guid);
|
|
Packit |
534379 |
if (FPGA_OK != result) {
|
|
Packit |
534379 |
OPAE_MSG("Failed to get PR interface id");
|
|
Packit |
534379 |
return result;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Discover the socket id from the FME's sysfs entry.
|
|
Packit |
534379 |
if (sysfs_path_is_valid(sysfspath, FPGA_SYSFS_SOCKET_ID) == FPGA_OK) {
|
|
Packit |
534379 |
|
|
Packit |
534379 |
resval = sysfs_parse_attribute64(sysfspath, FPGA_SYSFS_SOCKET_ID, &value);
|
|
Packit |
534379 |
if (resval != 0) {
|
|
Packit |
534379 |
return FPGA_NOT_FOUND;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
parent->socket_id = (uint8_t)value;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Read number of slots
|
|
Packit |
534379 |
resval = sysfs_parse_attribute64(sysfspath, FPGA_SYSFS_NUM_SLOTS, &value);
|
|
Packit |
534379 |
if (resval != 0) {
|
|
Packit |
534379 |
return FPGA_NOT_FOUND;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
pdev->fpga_num_slots = (uint32_t) value;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Read bitstream id
|
|
Packit |
534379 |
resval = sysfs_parse_attribute64(sysfspath, FPGA_SYSFS_BITSTREAM_ID, &pdev->fpga_bitstream_id);
|
|
Packit |
534379 |
if (resval != 0) {
|
|
Packit |
534379 |
return FPGA_NOT_FOUND;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
pdev->fpga_bbs_version.major =
|
|
Packit |
534379 |
FPGA_BBS_VER_MAJOR(pdev->fpga_bitstream_id);
|
|
Packit |
534379 |
pdev->fpga_bbs_version.minor =
|
|
Packit |
534379 |
FPGA_BBS_VER_MINOR(pdev->fpga_bitstream_id);
|
|
Packit |
534379 |
pdev->fpga_bbs_version.patch =
|
|
Packit |
534379 |
FPGA_BBS_VER_PATCH(pdev->fpga_bitstream_id);
|
|
Packit |
534379 |
|
|
Packit |
534379 |
parent->fme = pdev;
|
|
Packit |
534379 |
return FPGA_OK;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
STATIC fpga_result enum_afu(const char *sysfspath, const char *name,
|
|
Packit |
534379 |
struct dev_list *parent)
|
|
Packit |
534379 |
{
|
|
Packit |
534379 |
fpga_result result;
|
|
Packit |
534379 |
int resval = 0;
|
|
Packit |
534379 |
struct stat stats;
|
|
Packit |
534379 |
struct dev_list *pdev;
|
|
Packit |
534379 |
char spath[PATH_MAX] = { 0, };
|
|
Packit |
534379 |
char dpath[DEV_PATH_MAX] = { 0, };
|
|
Packit |
534379 |
uint64_t value = 0;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Make sure it's a directory.
|
|
Packit |
534379 |
if (stat(sysfspath, &stats) != 0) {
|
|
Packit |
534379 |
OPAE_ERR("stat failed: %s", strerror(errno));
|
|
Packit |
534379 |
return FPGA_NOT_FOUND;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (!S_ISDIR(stats.st_mode))
|
|
Packit |
534379 |
return FPGA_OK;
|
|
Packit |
534379 |
int res;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
snprintf(dpath, sizeof(dpath), FPGA_DEV_PATH "/%s", name);
|
|
Packit |
534379 |
|
|
Packit |
534379 |
pdev = add_dev(sysfspath, dpath, parent);
|
|
Packit |
534379 |
if (!pdev) {
|
|
Packit |
534379 |
OPAE_ERR("Failed to allocate device");
|
|
Packit |
534379 |
return FPGA_NO_MEMORY;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
pdev->objtype = FPGA_ACCELERATOR;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
pdev->segment = parent->segment;
|
|
Packit |
534379 |
pdev->bus = parent->bus;
|
|
Packit |
534379 |
pdev->device = parent->device;
|
|
Packit |
534379 |
pdev->function = parent->function;
|
|
Packit |
534379 |
pdev->vendor_id = parent->vendor_id;
|
|
Packit |
534379 |
pdev->device_id = parent->device_id;
|
|
Packit |
534379 |
pdev->socket_id = parent->socket_id = 0;
|
|
Packit |
534379 |
// get the socket id from the fme
|
|
Packit |
534379 |
if (sysfs_get_fme_path(sysfspath, spath) == FPGA_OK) {
|
|
Packit |
534379 |
resval = sysfs_parse_attribute64(spath, FPGA_SYSFS_SOCKET_ID, &value);
|
|
Packit |
534379 |
if (resval) {
|
|
Packit |
534379 |
OPAE_MSG("error reading socket_id");
|
|
Packit |
534379 |
} else {
|
|
Packit |
534379 |
pdev->socket_id = parent->socket_id = value;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
res = open(pdev->devpath, O_RDWR);
|
|
Packit |
534379 |
if (-1 == res) {
|
|
Packit |
534379 |
pdev->accelerator_state = FPGA_ACCELERATOR_ASSIGNED;
|
|
Packit |
534379 |
} else {
|
|
Packit |
534379 |
close(res);
|
|
Packit |
534379 |
pdev->accelerator_state = FPGA_ACCELERATOR_UNASSIGNED;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// FIXME: not to rely on hard-coded constants.
|
|
Packit |
534379 |
pdev->accelerator_num_mmios = 2;
|
|
Packit |
534379 |
pdev->accelerator_num_irqs = 0;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Discover the AFU GUID from sysfs.
|
|
Packit |
534379 |
snprintf(spath, sizeof(spath),
|
|
Packit |
534379 |
"%s/" FPGA_SYSFS_AFU_GUID, sysfspath);
|
|
Packit |
534379 |
|
|
Packit |
534379 |
result = sysfs_read_guid(spath, pdev->guid);
|
|
Packit |
534379 |
/* if we can't read the afu_id, remove device from list */
|
|
Packit |
534379 |
if (FPGA_OK != result) {
|
|
Packit |
534379 |
OPAE_MSG("Could not read afu_id from '%s', ignoring", spath);
|
|
Packit |
534379 |
parent->next = pdev->next;
|
|
Packit |
534379 |
free(pdev);
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
return FPGA_OK;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
typedef struct _enum_region_ctx{
|
|
Packit |
534379 |
struct dev_list *list;
|
|
Packit |
534379 |
bool include_port;
|
|
Packit |
534379 |
} enum_region_ctx;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
STATIC fpga_result enum_regions(const sysfs_fpga_device *device, void *context)
|
|
Packit |
534379 |
{
|
|
Packit |
534379 |
enum_region_ctx *ctx = (enum_region_ctx *)context;
|
|
Packit |
534379 |
fpga_result result = FPGA_OK;
|
|
Packit |
534379 |
struct dev_list *pdev = add_dev(device->sysfs_path, "", ctx->list);
|
|
Packit |
534379 |
if (!pdev) {
|
|
Packit |
534379 |
OPAE_MSG("Failed to allocate device");
|
|
Packit |
534379 |
return FPGA_NO_MEMORY;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
// Assign bus, function, device
|
|
Packit |
534379 |
// segment,device_id ,vendor_id
|
|
Packit |
534379 |
pdev->function = device->function;
|
|
Packit |
534379 |
pdev->segment = device->segment;
|
|
Packit |
534379 |
pdev->bus = device->bus;
|
|
Packit |
534379 |
pdev->device = device->device;
|
|
Packit |
534379 |
pdev->device_id = device->device_id;
|
|
Packit |
534379 |
pdev->vendor_id = device->vendor_id;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Enum fme
|
|
Packit |
534379 |
if (device->fme) {
|
|
Packit |
534379 |
result = enum_fme(device->fme->sysfs_path,
|
|
Packit |
534379 |
device->fme->sysfs_name, pdev);
|
|
Packit |
534379 |
if (result != FPGA_OK) {
|
|
Packit |
534379 |
OPAE_ERR("Failed to enum FME");
|
|
Packit |
534379 |
return result;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Enum port
|
|
Packit |
534379 |
if (device->port && ctx->include_port) {
|
|
Packit |
534379 |
result = enum_afu(device->port->sysfs_path,
|
|
Packit |
534379 |
device->port->sysfs_name, pdev);
|
|
Packit |
534379 |
if (result != FPGA_OK) {
|
|
Packit |
534379 |
OPAE_ERR("Failed to enum PORT");
|
|
Packit |
534379 |
return result;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
return FPGA_OK;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
STATIC fpga_result enum_fpga_region_resources(struct dev_list *list,
|
|
Packit |
534379 |
bool include_port)
|
|
Packit |
534379 |
{
|
|
Packit |
534379 |
enum_region_ctx ctx = {.list = list, .include_port = include_port};
|
|
Packit |
534379 |
|
|
Packit |
534379 |
return sysfs_foreach_device(enum_regions, &ctx;;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
|
|
Packit |
534379 |
/// Determine if filters require reading AFUs
|
|
Packit |
534379 |
///
|
|
Packit |
534379 |
/// Return true if any of the following conditions are met:
|
|
Packit |
534379 |
/// * The number of filters is zero
|
|
Packit |
534379 |
/// * At least one filter specifies FPGA_ACCELERATOR as object type
|
|
Packit |
534379 |
/// * At least one filter does NOT specify an object type
|
|
Packit |
534379 |
/// Return false otherwise
|
|
Packit |
534379 |
bool include_afu(const fpga_properties *filters, uint32_t num_filters)
|
|
Packit |
534379 |
{
|
|
Packit |
534379 |
size_t i = 0;
|
|
Packit |
534379 |
if (!num_filters)
|
|
Packit |
534379 |
return true;
|
|
Packit |
534379 |
for (i = 0; i < num_filters; ++i) {
|
|
Packit |
534379 |
struct _fpga_properties *_filter =
|
|
Packit |
534379 |
(struct _fpga_properties *)filters[i];
|
|
Packit |
534379 |
if (FIELD_VALID(_filter, FPGA_PROPERTY_OBJTYPE)) {
|
|
Packit |
534379 |
if (_filter->objtype == FPGA_ACCELERATOR) {
|
|
Packit |
534379 |
return true;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
} else {
|
|
Packit |
534379 |
return true;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
return false;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
fpga_result __XFPGA_API__ xfpga_fpgaEnumerate(const fpga_properties *filters,
|
|
Packit |
534379 |
uint32_t num_filters, fpga_token *tokens,
|
|
Packit |
534379 |
uint32_t max_tokens,
|
|
Packit |
534379 |
uint32_t *num_matches)
|
|
Packit |
534379 |
{
|
|
Packit |
534379 |
fpga_result result = FPGA_NOT_FOUND;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
|
|
Packit |
534379 |
struct dev_list head;
|
|
Packit |
534379 |
struct dev_list *lptr;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (NULL == num_matches) {
|
|
Packit |
534379 |
OPAE_MSG("num_matches is NULL");
|
|
Packit |
534379 |
return FPGA_INVALID_PARAM;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
/* requiring a max number of tokens, but not providing a pointer to
|
|
Packit |
534379 |
* return them through is invalid */
|
|
Packit |
534379 |
if ((max_tokens > 0) && (NULL == tokens)) {
|
|
Packit |
534379 |
OPAE_MSG("max_tokens > 0 with NULL tokens");
|
|
Packit |
534379 |
return FPGA_INVALID_PARAM;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if ((num_filters > 0) && (NULL == filters)) {
|
|
Packit |
534379 |
OPAE_MSG("num_filters > 0 with NULL filters");
|
|
Packit |
534379 |
return FPGA_INVALID_PARAM;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (!num_filters && (NULL != filters)) {
|
|
Packit |
534379 |
OPAE_MSG("num_filters == 0 with non-NULL filters");
|
|
Packit |
534379 |
return FPGA_INVALID_PARAM;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
*num_matches = 0;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
memset(&head, 0, sizeof(head));
|
|
Packit |
534379 |
|
|
Packit |
534379 |
//enum FPGA regions & resources
|
|
Packit |
534379 |
result = enum_fpga_region_resources(&head,
|
|
Packit |
534379 |
include_afu(filters, num_filters));
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (result != FPGA_OK) {
|
|
Packit |
534379 |
OPAE_MSG("No FPGA resources found");
|
|
Packit |
534379 |
return result;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
/* create and populate token data structures */
|
|
Packit |
534379 |
for (lptr = head.next; NULL != lptr; lptr = lptr->next) {
|
|
Packit |
534379 |
struct _fpga_token *_tok;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (!strnlen(lptr->devpath, sizeof(lptr->devpath)))
|
|
Packit |
534379 |
continue;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// propagate the socket_id field.
|
|
Packit |
534379 |
lptr->socket_id = lptr->parent->socket_id;
|
|
Packit |
534379 |
lptr->fme = lptr->parent->fme;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
/* FIXME: do we need to keep a global list of tokens? */
|
|
Packit |
534379 |
/* For now we do becaue it is used in xfpga_fpgaUpdateProperties
|
|
Packit |
534379 |
* to lookup a parent from the global list of tokens...*/
|
|
Packit |
534379 |
_tok = token_add(lptr->sysfspath, lptr->devpath);
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (NULL == _tok) {
|
|
Packit |
534379 |
OPAE_MSG("Failed to allocate memory for token");
|
|
Packit |
534379 |
result = FPGA_NO_MEMORY;
|
|
Packit |
534379 |
goto out_free_trash;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// FIXME: should check contents of filter for token magic
|
|
Packit |
534379 |
if (matches_filters(lptr, filters, num_filters)) {
|
|
Packit |
534379 |
if (*num_matches < max_tokens) {
|
|
Packit |
534379 |
if (xfpga_fpgaCloneToken(_tok, &tokens[*num_matches])
|
|
Packit |
534379 |
!= FPGA_OK) {
|
|
Packit |
534379 |
// FIXME: should we error out here?
|
|
Packit |
534379 |
OPAE_MSG("Error cloning token");
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
++(*num_matches);
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
out_free_trash:
|
|
Packit |
534379 |
/* FIXME: should this live in a separate function? */
|
|
Packit |
534379 |
for (lptr = head.next; NULL != lptr;) {
|
|
Packit |
534379 |
struct dev_list *trash = lptr;
|
|
Packit |
534379 |
lptr = lptr->next;
|
|
Packit |
534379 |
free(trash);
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
return result;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
fpga_result __XFPGA_API__ xfpga_fpgaCloneToken(fpga_token src, fpga_token *dst)
|
|
Packit |
534379 |
{
|
|
Packit |
534379 |
struct _fpga_token *_src = (struct _fpga_token *)src;
|
|
Packit |
534379 |
struct _fpga_token *_dst;
|
|
Packit |
534379 |
size_t len;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (NULL == src || NULL == dst) {
|
|
Packit |
534379 |
OPAE_MSG("src or dst in NULL");
|
|
Packit |
534379 |
return FPGA_INVALID_PARAM;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (_src->magic != FPGA_TOKEN_MAGIC) {
|
|
Packit |
534379 |
OPAE_MSG("Invalid src");
|
|
Packit |
534379 |
return FPGA_INVALID_PARAM;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
_dst = calloc(1, sizeof(struct _fpga_token));
|
|
Packit |
534379 |
if (NULL == _dst) {
|
|
Packit |
534379 |
OPAE_MSG("Failed to allocate memory for token");
|
|
Packit |
534379 |
return FPGA_NO_MEMORY;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
_dst->magic = FPGA_TOKEN_MAGIC;
|
|
Packit |
534379 |
_dst->device_instance = _src->device_instance;
|
|
Packit |
534379 |
_dst->subdev_instance = _src->subdev_instance;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
len = strnlen(_src->sysfspath, sizeof(_src->sysfspath) - 1);
|
|
Packit |
534379 |
strncpy(_dst->sysfspath, _src->sysfspath, len + 1);
|
|
Packit |
534379 |
|
|
Packit |
534379 |
len = strnlen(_src->devpath, sizeof(_src->devpath) - 1);
|
|
Packit |
534379 |
strncpy(_dst->devpath, _src->devpath, len + 1);
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// shallow-copy error list
|
|
Packit |
534379 |
_dst->errors = _src->errors;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
*dst = _dst;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
return FPGA_OK;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
fpga_result __XFPGA_API__ xfpga_fpgaDestroyToken(fpga_token *token)
|
|
Packit |
534379 |
{
|
|
Packit |
534379 |
fpga_result result = FPGA_OK;
|
|
Packit |
534379 |
int err = 0;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (NULL == token || NULL == *token) {
|
|
Packit |
534379 |
OPAE_MSG("Invalid token pointer");
|
|
Packit |
534379 |
return FPGA_INVALID_PARAM;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
struct _fpga_token *_token = (struct _fpga_token *)*token;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (pthread_mutex_lock(&global_lock)) {
|
|
Packit |
534379 |
OPAE_MSG("Failed to lock global mutex");
|
|
Packit |
534379 |
return FPGA_EXCEPTION;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
if (_token->magic != FPGA_TOKEN_MAGIC) {
|
|
Packit |
534379 |
OPAE_MSG("Invalid token");
|
|
Packit |
534379 |
result = FPGA_INVALID_PARAM;
|
|
Packit |
534379 |
goto out_unlock;
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// invalidate magic (just in case)
|
|
Packit |
534379 |
_token->magic = FPGA_INVALID_MAGIC;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
free(*token);
|
|
Packit |
534379 |
*token = NULL;
|
|
Packit |
534379 |
|
|
Packit |
534379 |
out_unlock:
|
|
Packit |
534379 |
err = pthread_mutex_unlock(&global_lock);
|
|
Packit |
534379 |
if (err) {
|
|
Packit |
534379 |
OPAE_ERR("pthread_mutex_unlock() failed: %S", strerror(err));
|
|
Packit |
534379 |
}
|
|
Packit |
534379 |
return result;
|
|
Packit |
534379 |
}
|