File hello_events.c¶
File List > docs > sw > samples > hello_events > hello_events.c
Go to the documentation of this file.
// Copyright(c) 2017-2021, Intel Corporation
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of Intel Corporation nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <poll.h>
#include <errno.h>
#include <sys/stat.h>
#include <pthread.h>
#include <opae/fpga.h>
#include <argsfilter.h>
#include "mock/opae_std.h"
int usleep(unsigned);
#define FME_SYSFS_INJECT_ERROR "errors/inject_errors"
#define ON_ERR_GOTO(res, label, desc) \
do { \
if ((res) != FPGA_OK) { \
print_err((desc), (res)); \
goto label; \
} \
} while (0)
void print_err(const char *s, fpga_result res)
{
fprintf(stderr, "Error %s: %s\n", s, fpgaErrStr(res));
}
// RAS Error Inject CSR
struct ras_inject_error {
union {
uint64_t csr;
struct {
/* Catastrophic error */
uint64_t catastrophicr_error : 1;
/* Fatal error */
uint64_t fatal_error : 1;
/* Non-fatal error */
uint64_t nonfatal_error : 1;
/* Reserved */
uint64_t rsvd : 61;
};
};
};
fpga_result inject_ras_fatal_error(fpga_token fme_token, uint8_t err)
{
fpga_result res1 = FPGA_OK;
fpga_result res2 = FPGA_OK;
fpga_handle fme_handle = NULL;
struct ras_inject_error inj_error = { {0} };
fpga_object inj_err_object;
res1 = fpgaOpen(fme_token, &fme_handle, FPGA_OPEN_SHARED);
if (res1 != FPGA_OK) {
OPAE_ERR("Failed to open FPGA");
return res1;
}
res1 = fpgaHandleGetObject(fme_handle, FME_SYSFS_INJECT_ERROR, &inj_err_object, 0);
ON_ERR_GOTO(res1, out_close, "Failed to get Handle Object");
// Inject fatal error
inj_error.fatal_error = err;
res1 = fpgaObjectWrite64(inj_err_object, inj_error.csr, 0);
ON_ERR_GOTO(res1, out_destroy_obj, "Failed to Read Object");
out_destroy_obj:
res2 = fpgaDestroyObject(&inj_err_object);
ON_ERR_GOTO(res2, out_close, "Failed to Destroy Object");
out_close:
res2 = fpgaClose(fme_handle);
if (res2 != FPGA_OK) {
OPAE_ERR("Failed to close FPGA");
}
return res1 != FPGA_OK ? res1 : res2;
}
void *error_thread(void *arg)
{
fpga_token token = (fpga_token) arg;
fpga_result res;
usleep(5000000);
printf("injecting error\n");
res = inject_ras_fatal_error(token, 1);
if (res != FPGA_OK)
print_err("setting inject error register", res);
usleep(5000000);
printf("clearing error\n");
res = inject_ras_fatal_error(token, 0);
if (res != FPGA_OK)
print_err("clearing inject error register", res);
return NULL;
}
void help(void)
{
printf("\n"
"hello_events\n"
"OPAE Events API sample\n"
"\n"
"Usage:\n"
" hello_events [-hv] [-S <segment>] [-B <bus>] [-D <device>] [-F <function>] [PCI_ADDR]\n"
"\n"
" -h,--help Print this help\n"
" -v,--version Print version info and exit\n"
"\n");
}
/*
* Parse command line arguments
*/
#define GETOPT_STRING "hv"
fpga_result parse_args(int argc, char *argv[])
{
struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
};
int getopt_ret;
int option_index;
while (-1 != (getopt_ret = getopt_long(argc, argv, GETOPT_STRING, longopts, &option_index))) {
const char *tmp_optarg = optarg;
/* checks to see if optarg is null and if not goes to value of optarg */
if ((optarg) && ('=' == *tmp_optarg)) {
++tmp_optarg;
}
switch (getopt_ret) {
case 'h': /* help */
help();
return -1;
case 'v': /* version */
printf("hello_events %s %s%s\n",
OPAE_VERSION,
OPAE_GIT_COMMIT_HASH,
OPAE_GIT_SRC_TREE_DIRTY ? "*":"");
return -1;
default: /* invalid option */
fprintf(stderr, "Invalid cmdline options\n");
return FPGA_EXCEPTION;
}
}
return FPGA_OK;
}
fpga_result find_fpga(fpga_properties device_filter,
fpga_token *fpga,
uint32_t *num_matches)
{
fpga_properties filter = NULL;
fpga_result res = FPGA_OK;
fpga_result dres = FPGA_OK;
res = fpgaCloneProperties(device_filter, &filter);
ON_ERR_GOTO(res, out, "cloning properties object");
res = fpgaPropertiesSetObjectType(filter, FPGA_DEVICE);
ON_ERR_GOTO(res, out_destroy, "setting interface ID");
res = fpgaEnumerate(&filter, 1, fpga, 1, num_matches);
ON_ERR_GOTO(res, out_destroy, "enumerating FPGAs");
out_destroy:
dres = fpgaDestroyProperties(&filter);
ON_ERR_GOTO(dres, out, "destroying properties object");
out:
return (res == FPGA_OK) ? dres : res;
}
int main(int argc, char *argv[])
{
fpga_token fpga_device_token = NULL;
fpga_handle fpga_device_handle = NULL;
uint32_t num_matches = 1;
fpga_result res1 = FPGA_OK;
fpga_result res2 = FPGA_OK;
fpga_event_handle eh;
uint64_t count = 0;
int res;
struct pollfd pfd;
int timeout = 10000;
int poll_ret = 0;
ssize_t bytes_read = 0;
pthread_t errthr;
fpga_properties device_filter = NULL;
res1 = fpgaGetProperties(NULL, &device_filter);
if (res1) {
print_err("failed to alloc properties", res1);
return res1;
}
if (opae_set_properties_from_args(device_filter,
&res1,
&argc,
argv)) {
print_err("failed arg parse", res1);
res1 = FPGA_EXCEPTION;
goto out_exit;
} else if (res1) {
print_err("failed to set properties", res1);
goto out_exit;
}
res1 = parse_args(argc, argv);
if ((int)res1 < 0)
goto out_exit;
ON_ERR_GOTO(res1, out_exit, "parsing arguments");
res1 = find_fpga(device_filter, &fpga_device_token, &num_matches);
ON_ERR_GOTO(res1, out_exit, "finding FPGA accelerator");
if (num_matches < 1) {
fprintf(stderr, "No matches for address provided.\n");
res1 = FPGA_NOT_FOUND;
goto out_exit;
}
if (num_matches > 1) {
fprintf(stderr, "Found more than one suitable slot.\n");
}
res1 = fpgaOpen(fpga_device_token, &fpga_device_handle, FPGA_OPEN_SHARED);
ON_ERR_GOTO(res1, out_destroy_tok, "opening accelerator");
res1 = fpgaCreateEventHandle(&eh);
ON_ERR_GOTO(res1, out_close, "creating event handle");
res1 = fpgaRegisterEvent(fpga_device_handle, FPGA_EVENT_ERROR, eh, 0);
ON_ERR_GOTO(res1, out_destroy_eh, "registering an FME event");
printf("Waiting for interrupts now...\n");
res = pthread_create(&errthr, NULL, error_thread, fpga_device_token);
if (res) {
printf("Failed to create error_thread.\n");
res1 = FPGA_EXCEPTION;
goto out_destroy_eh;
}
res1 = fpgaGetOSObjectFromEventHandle(eh, &pfd.fd);
ON_ERR_GOTO(res1, out_join, "getting file descriptor");
pfd.events = POLLIN;
poll_ret = poll(&pfd, 1, timeout);
if (poll_ret < 0) {
printf("Poll error errno = %s\n", strerror(errno));
res1 = FPGA_EXCEPTION;
goto out_join;
} else if (poll_ret == 0) {
printf("Poll timeout occurred\n");
res1 = FPGA_EXCEPTION;
goto out_join;
} else {
printf("FME Interrupt occurred\n");
bytes_read = opae_read(pfd.fd, &count, sizeof(count));
if (bytes_read <= 0)
printf("WARNING: error reading from poll fd: %s\n",
bytes_read < 0 ? strerror(errno) : "zero bytes read");
}
res1 = fpgaUnregisterEvent(fpga_device_handle, FPGA_EVENT_ERROR, eh);
ON_ERR_GOTO(res1, out_join, "unregistering an FME event");
printf("Successfully tested Register/Unregister for FME events!\n");
out_join:
pthread_join(errthr, NULL);
out_destroy_eh:
res2 = fpgaDestroyEventHandle(&eh);
ON_ERR_GOTO(res2, out_close, "deleting event handle");
out_close:
res2 = fpgaClose(fpga_device_handle);
ON_ERR_GOTO(res2, out_destroy_tok, "closing accelerator");
out_destroy_tok:
res2 = fpgaDestroyToken(&fpga_device_token);
ON_ERR_GOTO(res2, out_exit, "destroying token");
out_exit:
fpgaDestroyProperties(&device_filter);
return res1 != FPGA_OK ? res1 : res2;
}