Blame opae-libs/plugins/xfpga/enum.c

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
}