Blame tools/fpgad/monitored_device.c

Packit Service 3975d1
// Copyright(c) 2018-2020, Intel Corporation
Packit Service 3975d1
//
Packit Service 3975d1
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
Packit Service 3975d1
// modification, are permitted provided that the following conditions are met:
Packit Service 3975d1
//
Packit Service 3975d1
// * Redistributions of  source code  must retain the  above copyright notice,
Packit Service 3975d1
//   this list of conditions and the following disclaimer.
Packit Service 3975d1
// * Redistributions in binary form must reproduce the above copyright notice,
Packit Service 3975d1
//   this list of conditions and the following disclaimer in the documentation
Packit Service 3975d1
//   and/or other materials provided with the distribution.
Packit Service 3975d1
// * Neither the name  of Intel Corporation  nor the names of its contributors
Packit Service 3975d1
//   may be used to  endorse or promote  products derived  from this  software
Packit Service 3975d1
//   without specific prior written permission.
Packit Service 3975d1
//
Packit Service 3975d1
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit Service 3975d1
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
Packit Service 3975d1
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit Service 3975d1
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
Packit Service 3975d1
// LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
Packit Service 3975d1
// CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
Packit Service 3975d1
// SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
Packit Service 3975d1
// INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
Packit Service 3975d1
// CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
Packit Service 3975d1
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
Packit Service 3975d1
// POSSIBILITY OF SUCH DAMAGE.
Packit Service 3975d1
Packit Service 3975d1
#ifdef HAVE_CONFIG_H
Packit Service 3975d1
#include <config.h>
Packit Service 3975d1
#endif // HAVE_CONFIG_H
Packit Service 3975d1
Packit Service 3975d1
#include <stdio.h>
Packit Service 3975d1
#include <linux/limits.h>
Packit Service 3975d1
#include <dlfcn.h>
Packit Service 3975d1
#include <glob.h>
Packit Service 3975d1
Packit Service 3975d1
#include <uuid/uuid.h>
Packit Service 3975d1
Packit Service 3975d1
#include "monitored_device.h"
Packit Service 3975d1
#include "monitor_thread.h"
Packit Service 3975d1
#include "api/sysfs.h"
Packit Service 3975d1
Packit Service 3975d1
#ifdef LOG
Packit Service 3975d1
#undef LOG
Packit Service 3975d1
#endif
Packit Service 3975d1
#define LOG(format, ...) \
Packit Service 3975d1
log_printf("monitored_device: " format, ##__VA_ARGS__)
Packit Service 3975d1
Packit Service 3975d1
fpgad_supported_device default_supported_devices_table[] = {
Packit Service 3975d1
	{ 0x8086, 0xbcc0, "libfpgad-xfpga.so", 0, NULL, "" },
Packit Service 3975d1
	{ 0x8086, 0xbcc1, "libfpgad-xfpga.so", 0, NULL, "" },
Packit Service 3975d1
	{ 0x8086, 0x0b30,    "libfpgad-vc.so", 0, NULL, "" },
Packit Service 3975d1
	{ 0x8086, 0x0b31,    "libfpgad-vc.so", 0, NULL, "" },
Packit Service 3975d1
	{      0,      0,                NULL, 0, NULL, "" },
Packit Service 3975d1
};
Packit Service 3975d1
Packit Service 3975d1
STATIC fpgad_supported_device *mon_is_loaded(struct fpgad_config *c,
Packit Service 3975d1
					     const char *library_path)
Packit Service 3975d1
{
Packit Service 3975d1
	unsigned i;
Packit Service 3975d1
	int res = 0;
Packit Service 3975d1
Packit Service 3975d1
	for (i = 0 ; c->supported_devices[i].library_path ; ++i) {
Packit Service 3975d1
		fpgad_supported_device *d = &c->supported_devices[i];
Packit Service 3975d1
Packit Service 3975d1
		res = strcmp(library_path, d->library_path);
Packit Service 3975d1
Packit Service 3975d1
		if (!res && (d->flags & FPGAD_DEV_LOADED))
Packit Service 3975d1
			return d;
Packit Service 3975d1
	}
Packit Service 3975d1
	return NULL;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC fpgad_monitored_device *
Packit Service 3975d1
allocate_monitored_device(struct fpgad_config *config,
Packit Service 3975d1
			  fpgad_supported_device *supported,
Packit Service 3975d1
			  fpga_token token,
Packit Service 3975d1
			  uint64_t object_id,
Packit Service 3975d1
			  fpga_objtype object_type,
Packit Service 3975d1
			  opae_bitstream_info *bitstr)
Packit Service 3975d1
{
Packit Service 3975d1
	fpgad_monitored_device *d;
Packit Service 3975d1
Packit Service 3975d1
	d = (fpgad_monitored_device *) calloc(
Packit Service 3975d1
			1, sizeof(fpgad_monitored_device));
Packit Service 3975d1
Packit Service 3975d1
	if (!d) {
Packit Service 3975d1
		LOG("out of memory");
Packit Service 3975d1
		return NULL;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	d->config = config;
Packit Service 3975d1
	d->supported = supported;
Packit Service 3975d1
	d->token = token;
Packit Service 3975d1
	d->object_id = object_id;
Packit Service 3975d1
	d->object_type = object_type;
Packit Service 3975d1
	d->bitstr = bitstr;
Packit Service 3975d1
Packit Service 3975d1
	return d;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC void *mon_find_plugin(const char *libpath)
Packit Service 3975d1
{
Packit Service 3975d1
	char plugin_path[PATH_MAX];
Packit Service 3975d1
	const char *search_paths[] = { OPAE_MODULE_SEARCH_PATHS };
Packit Service 3975d1
	unsigned i;
Packit Service 3975d1
	void *dl_handle;
Packit Service 3975d1
Packit Service 3975d1
	for (i = 0 ;
Packit Service 3975d1
		i < sizeof(search_paths) / sizeof(search_paths[0]) ;
Packit Service 3975d1
		++i) {
Packit Service 3975d1
		snprintf(plugin_path, sizeof(plugin_path),
Packit Service 3975d1
				"%s%s", search_paths[i], libpath);
Packit Service 3975d1
Packit Service 3975d1
		dl_handle = dlopen(plugin_path, RTLD_LAZY|RTLD_LOCAL);
Packit Service 3975d1
		if (dl_handle)
Packit Service 3975d1
			return dl_handle;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	return NULL;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC bool mon_consider_device(struct fpgad_config *c, fpga_token token)
Packit Service 3975d1
{
Packit Service 3975d1
	unsigned i;
Packit Service 3975d1
	fpga_properties props = NULL;
Packit Service 3975d1
	fpga_token parent = NULL;
Packit Service 3975d1
	fpga_properties parent_props = NULL;
Packit Service 3975d1
	fpga_result res;
Packit Service 3975d1
	uint16_t vendor_id;
Packit Service 3975d1
	uint16_t device_id;
Packit Service 3975d1
	uint64_t object_id;
Packit Service 3975d1
	fpga_objtype object_type;
Packit Service 3975d1
	opae_bitstream_info *bitstr = NULL;
Packit Service 3975d1
	fpga_guid pr_ifc_id;
Packit Service 3975d1
	bool added = false;
Packit Service 3975d1
Packit Service 3975d1
	res = fpgaGetProperties(token, &props;;
Packit Service 3975d1
	if (res != FPGA_OK) {
Packit Service 3975d1
		LOG("failed to get properties\n");
Packit Service 3975d1
		return false;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	vendor_id = 0;
Packit Service 3975d1
	res = fpgaPropertiesGetVendorID(props, &vendor_id);
Packit Service 3975d1
	if (res != FPGA_OK) {
Packit Service 3975d1
		LOG("failed to get vendor ID\n");
Packit Service 3975d1
		goto err_out_destroy;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	device_id = 0;
Packit Service 3975d1
	res = fpgaPropertiesGetDeviceID(props, &device_id);
Packit Service 3975d1
	if (res != FPGA_OK) {
Packit Service 3975d1
		LOG("failed to get device ID\n");
Packit Service 3975d1
		goto err_out_destroy;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	object_id = 0;
Packit Service 3975d1
	res = fpgaPropertiesGetObjectID(props, &object_id);
Packit Service 3975d1
	if (res != FPGA_OK) {
Packit Service 3975d1
		LOG("failed to get object ID\n");
Packit Service 3975d1
		goto err_out_destroy;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	object_type = FPGA_ACCELERATOR;
Packit Service 3975d1
	res = fpgaPropertiesGetObjectType(props, &object_type);
Packit Service 3975d1
	if (res != FPGA_OK) {
Packit Service 3975d1
		LOG("failed to get object type\n");
Packit Service 3975d1
		goto err_out_destroy;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	// Do we have a NULL GBS from the command line
Packit Service 3975d1
	// that matches this device?
Packit Service 3975d1
Packit Service 3975d1
	if (object_type == FPGA_DEVICE) {
Packit Service 3975d1
		// The token's guid is the PR interface ID.
Packit Service 3975d1
Packit Service 3975d1
		res = fpgaPropertiesGetGUID(props, &pr_ifc_id);
Packit Service 3975d1
		if (res != FPGA_OK) {
Packit Service 3975d1
			LOG("failed to get PR interface ID\n");\
Packit Service 3975d1
			goto err_out_destroy;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		for (i = 0 ; i < c->num_null_gbs ; ++i) {
Packit Service 3975d1
			if (!uuid_compare(c->null_gbs[i].pr_interface_id,
Packit Service 3975d1
					  pr_ifc_id)) {
Packit Service 3975d1
				bitstr = &c->null_gbs[i];
Packit Service 3975d1
				break;
Packit Service 3975d1
			}
Packit Service 3975d1
		}
Packit Service 3975d1
	} else {
Packit Service 3975d1
		// The parent token's guid is the PR interface ID.
Packit Service 3975d1
Packit Service 3975d1
		res = fpgaPropertiesGetParent(props, &parent);
Packit Service 3975d1
		if (res != FPGA_OK) {
Packit Service 3975d1
			LOG("failed to get parent token\n");
Packit Service 3975d1
			goto err_out_destroy;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		res = fpgaGetProperties(parent, &parent_props);
Packit Service 3975d1
		if (res != FPGA_OK) {
Packit Service 3975d1
			LOG("failed to get parent properties\n");
Packit Service 3975d1
			goto err_out_destroy;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		res = fpgaPropertiesGetGUID(parent_props, &pr_ifc_id);
Packit Service 3975d1
		if (res != FPGA_OK) {
Packit Service 3975d1
			LOG("failed to get PR interface ID\n");
Packit Service 3975d1
			goto err_out_destroy;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		fpgaDestroyProperties(&parent_props);
Packit Service 3975d1
		fpgaDestroyToken(&parent);
Packit Service 3975d1
Packit Service 3975d1
		for (i = 0 ; i < c->num_null_gbs ; ++i) {
Packit Service 3975d1
			if (!uuid_compare(c->null_gbs[i].pr_interface_id,
Packit Service 3975d1
					  pr_ifc_id)) {
Packit Service 3975d1
				bitstr = &c->null_gbs[i];
Packit Service 3975d1
				break;
Packit Service 3975d1
			}
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	fpgaDestroyProperties(&props;;
Packit Service 3975d1
Packit Service 3975d1
	for (i = 0 ; c->supported_devices[i].library_path ; ++i) {
Packit Service 3975d1
		fpgad_supported_device *d = &c->supported_devices[i];
Packit Service 3975d1
Packit Service 3975d1
		// Do we support this device?
Packit Service 3975d1
		if (d->vendor_id == vendor_id &&
Packit Service 3975d1
		    d->device_id == device_id) {
Packit Service 3975d1
			fpgad_supported_device *loaded_by;
Packit Service 3975d1
			fpgad_monitored_device *monitored;
Packit Service 3975d1
			fpgad_plugin_configure_t cfg;
Packit Service 3975d1
			int res;
Packit Service 3975d1
Packit Service 3975d1
			d->flags |= FPGAD_DEV_DETECTED;
Packit Service 3975d1
Packit Service 3975d1
			// Is the fpgad plugin already loaded?
Packit Service 3975d1
			loaded_by = mon_is_loaded(c, d->library_path);
Packit Service 3975d1
Packit Service 3975d1
			if (loaded_by) {
Packit Service 3975d1
				// The two table entries will share the
Packit Service 3975d1
				// same plugin handle (but only loaded_by
Packit Service 3975d1
				// will have FPGAD_DEV_LOADED).
Packit Service 3975d1
				d->dl_handle = loaded_by->dl_handle;
Packit Service 3975d1
			} else {
Packit Service 3975d1
				// Plugin hasn't been loaded.
Packit Service 3975d1
				// Load it now.
Packit Service 3975d1
				d->dl_handle =
Packit Service 3975d1
					mon_find_plugin(d->library_path);
Packit Service 3975d1
				if (!d->dl_handle) {
Packit Service 3975d1
					char *err = dlerror();
Packit Service 3975d1
					LOG("failed to load \"%s\" %s\n",
Packit Service 3975d1
							d->library_path,
Packit Service 3975d1
							err ? err : "");
Packit Service 3975d1
					continue;
Packit Service 3975d1
				}
Packit Service 3975d1
Packit Service 3975d1
				d->flags |= FPGAD_DEV_LOADED;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			if (!bitstr) {
Packit Service 3975d1
				LOG("Warning: no NULL GBS for vid=0x%04x "
Packit Service 3975d1
					"did=0x%04x objid=0x%x (%s)\n",
Packit Service 3975d1
				vendor_id,
Packit Service 3975d1
				device_id,
Packit Service 3975d1
				object_id,
Packit Service 3975d1
				object_type == FPGA_ACCELERATOR ?
Packit Service 3975d1
				"accelerator" : "device");
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			// Add the device to the monitored list.
Packit Service 3975d1
			monitored = allocate_monitored_device(c,
Packit Service 3975d1
							      d,
Packit Service 3975d1
							      token,
Packit Service 3975d1
							      object_id,
Packit Service 3975d1
							      object_type,
Packit Service 3975d1
							      bitstr);
Packit Service 3975d1
			if (!monitored) {
Packit Service 3975d1
				LOG("failed to add device 0x%04x:0x%04x\n",
Packit Service 3975d1
					vendor_id, device_id);
Packit Service 3975d1
				continue;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			// Success
Packit Service 3975d1
			cfg = (fpgad_plugin_configure_t)
Packit Service 3975d1
				dlsym(d->dl_handle,
Packit Service 3975d1
				      FPGAD_PLUGIN_CONFIGURE);
Packit Service 3975d1
			if (!cfg) {
Packit Service 3975d1
				LOG("failed to find %s in \"%s\"\n",
Packit Service 3975d1
					FPGAD_PLUGIN_CONFIGURE,
Packit Service 3975d1
					d->library_path);
Packit Service 3975d1
				free(monitored);
Packit Service 3975d1
				continue;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			res = cfg(monitored, d->config);
Packit Service 3975d1
			if (res) {
Packit Service 3975d1
				LOG("%s for \"%s\" returned %d.\n",
Packit Service 3975d1
				    FPGAD_PLUGIN_CONFIGURE,
Packit Service 3975d1
				    d->library_path,
Packit Service 3975d1
				    res);
Packit Service 3975d1
				free(monitored);
Packit Service 3975d1
				continue;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			if (monitored->type == FPGAD_PLUGIN_TYPE_THREAD) {
Packit Service 3975d1
Packit Service 3975d1
				if (monitored->thread_fn) {
Packit Service 3975d1
Packit Service 3975d1
					if (pthread_create(&monitored->thread,
Packit Service 3975d1
							   NULL,
Packit Service 3975d1
							   monitored->thread_fn,
Packit Service 3975d1
							   monitored)) {
Packit Service 3975d1
						LOG("failed to create thread"
Packit Service 3975d1
						    " for \"%s\"\n",
Packit Service 3975d1
						    d->library_path);
Packit Service 3975d1
						free(monitored);
Packit Service 3975d1
						continue;
Packit Service 3975d1
					}
Packit Service 3975d1
Packit Service 3975d1
				} else {
Packit Service 3975d1
					LOG("Thread plugin \"%s\" has no "
Packit Service 3975d1
					    "thread_fn\n", d->library_path);
Packit Service 3975d1
					free(monitored);
Packit Service 3975d1
					continue;
Packit Service 3975d1
				}
Packit Service 3975d1
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			mon_monitor_device(monitored);
Packit Service 3975d1
			added = true;
Packit Service 3975d1
			break;
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	return added;
Packit Service 3975d1
Packit Service 3975d1
err_out_destroy:
Packit Service 3975d1
	if (props)
Packit Service 3975d1
		fpgaDestroyProperties(&props;;
Packit Service 3975d1
	if (parent)
Packit Service 3975d1
		fpgaDestroyToken(&parent);
Packit Service 3975d1
	if (parent_props)
Packit Service 3975d1
		fpgaDestroyProperties(&parent_props);
Packit Service 3975d1
	return false;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
int mon_enumerate(struct fpgad_config *c)
Packit Service 3975d1
{
Packit Service 3975d1
	fpga_token *tokens = NULL;
Packit Service 3975d1
	fpga_result res;
Packit Service 3975d1
	uint32_t num_matches = 0;
Packit Service 3975d1
	uint32_t i;
Packit Service 3975d1
	unsigned monitored_devices = 0;
Packit Service 3975d1
Packit Service 3975d1
	res = fpgaEnumerate(NULL, 0, NULL, 0, &num_matches);
Packit Service 3975d1
	if (res != FPGA_OK) {
Packit Service 3975d1
		LOG("enumeration failed\n");
Packit Service 3975d1
		return res;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!num_matches) {
Packit Service 3975d1
		res = 1;
Packit Service 3975d1
		return res;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	tokens = calloc(num_matches, sizeof(fpga_token));
Packit Service 3975d1
	if (!tokens) {
Packit Service 3975d1
		res = 1;
Packit Service 3975d1
		LOG("out of memory\n");
Packit Service 3975d1
		return res;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	res = fpgaEnumerate(NULL, 0, tokens, num_matches, &num_matches);
Packit Service 3975d1
	if (res != FPGA_OK) {
Packit Service 3975d1
		LOG("enumeration failed (2)\n");
Packit Service 3975d1
		goto out_exit;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	for (i = 0 ; i < num_matches ; ++i) {
Packit Service 3975d1
		if (!mon_consider_device(c, tokens[i])) {
Packit Service 3975d1
			// Not monitoring it. Destroy the token.
Packit Service 3975d1
			fpgaDestroyToken(&tokens[i]);
Packit Service 3975d1
		} else {
Packit Service 3975d1
			++monitored_devices;
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
out_exit:
Packit Service 3975d1
	if (tokens)
Packit Service 3975d1
		free(tokens);
Packit Service 3975d1
	return res + (monitored_devices ? 0 : 1);
Packit Service 3975d1
}