17 #include "libocxl_internal.h" 23 #include <misc/ocxl.h> 24 #include <sys/eventfd.h> 25 #include <sys/ioctl.h> 27 #include <sys/select.h> 29 #include <sys/sysmacros.h> 30 #include <sys/types.h> 33 #include <sys/epoll.h> 62 ocxl_afu *my_afu = (ocxl_afu *) afu;
79 ocxl_afu *my_afu = (ocxl_afu *) afu;
81 return &my_afu->identifier;
97 ocxl_afu *my_afu = (ocxl_afu *) afu;
99 return my_afu->device_path;
113 ocxl_afu *my_afu = (ocxl_afu *) afu;
115 return my_afu->sysfs_path;
131 ocxl_afu *my_afu = (ocxl_afu *) afu;
133 *major = my_afu->version_major;
134 *minor = my_afu->version_minor;
163 ocxl_afu *my_afu = (ocxl_afu *) afu;
165 my_afu->verbose_errors = !!(sources &
OCXL_ERRORS);
188 const char *message))
190 ocxl_afu *my_afu = (ocxl_afu *) afu;
192 my_afu->error_handler = handler;
222 static void afu_init(ocxl_afu *afu)
224 memset((
char *)afu->identifier.afu_name,
'\0',
sizeof(afu->identifier.afu_name));
225 afu->device_path = NULL;
226 afu->sysfs_path = NULL;
227 afu->version_major = 0;
228 afu->version_minor = 0;
230 afu->fd_info.type = EPOLL_SOURCE_OCXL;
231 afu->fd_info.irq = NULL;
233 afu->epoll_events = NULL;
234 afu->epoll_event_count = 0;
235 afu->global_mmio_fd = -1;
237 afu->global_mmio.start = NULL;
238 afu->global_mmio.length = 0;
241 afu->per_pasid_mmio.start = NULL;
242 afu->per_pasid_mmio.length = 0;
245 afu->page_size = sysconf(_SC_PAGESIZE);
249 afu->irq_max_count = 0;
253 afu->mmio_max_count = 0;
255 afu->pasid = UINT32_MAX;
257 afu->verbose_errors =
false;
258 afu->error_handler = ocxl_default_afu_error_handler;
260 afu->tracing =
false;
279 ocxl_afu *afu = malloc(
sizeof(ocxl_afu));
282 errmsg(NULL, rc,
"Could not allocate %d bytes for AFU",
sizeof(ocxl_afu));
302 static bool device_matches(
int dirfd,
char *dev_name, dev_t dev)
306 if (fstatat(dirfd, dev_name, &sb, 0) == -1) {
310 if (!S_ISCHR(sb.st_mode)) {
314 return dev == sb.st_rdev;
325 static bool populate_metadata(dev_t dev, ocxl_afu *afu)
328 struct dirent *dev_ent;
330 dev_dir = opendir(DEVICE_PATH);
332 if (dev_dir == NULL) {
336 int fd = dirfd(dev_dir);
338 if (!(dev_ent = readdir(dev_dir))) {
342 }
while (!device_matches(fd, dev_ent->d_name, dev));
344 char *physical_function = strchr(dev_ent->d_name,
'.');
345 if (physical_function == NULL) {
346 errmsg(NULL,
OCXL_INTERNAL_ERROR,
"Could not extract physical function from device name '%s', missing initial '.'",
350 int afu_name_len = physical_function - dev_ent->d_name;
352 errmsg(NULL,
OCXL_INTERNAL_ERROR,
"AFU name '%-.*s' exceeds maximum length of %d", afu_name_len, dev_ent->d_name);
358 uint8_t bus, device,
function;
359 int found = sscanf(physical_function,
"%hu:%hhu:%hhu.%hhu.%hhu",
360 &domain, &bus, &device, &
function, &afu->identifier.afu_index);
363 errmsg(NULL,
OCXL_INTERNAL_ERROR,
"Could not parse physical function '%s', only got %d components", physical_function,
368 memcpy((
char *)afu->identifier.afu_name, dev_ent->d_name, afu_name_len);
369 ((
char *)afu->identifier.afu_name)[afu_name_len] =
'\0';
371 size_t dev_path_len = strlen(DEVICE_PATH) + 1 + strlen(dev_ent->d_name) + 1;
372 afu->device_path = malloc(dev_path_len);
373 if (NULL == afu->device_path) {
374 errmsg(NULL,
OCXL_INTERNAL_ERROR,
"Could not allocate %llu bytes for device path", dev_path_len);
377 (void)snprintf(afu->device_path, dev_path_len,
"%s/%s", DEVICE_PATH, dev_ent->d_name);
379 size_t sysfs_path_len = strlen(SYS_PATH) + 1 + strlen(dev_ent->d_name) + 1;
380 afu->sysfs_path = malloc(sysfs_path_len);
381 if (NULL == afu->sysfs_path) {
382 errmsg(NULL,
OCXL_INTERNAL_ERROR,
"Could not allocate %llu bytes for sysfs path", sysfs_path_len);
385 (void)snprintf(afu->sysfs_path, sysfs_path_len,
"%s/%s", SYS_PATH, dev_ent->d_name);
395 static void trace_metadata(ocxl_afu *afu)
397 TRACE(afu,
"device path=\"%s\"", afu->device_path);
398 TRACE(afu,
"sysfs path=\"%s\"", afu->sysfs_path);
399 TRACE(afu,
"AFU Name=\"%s\"", afu->identifier.afu_name);
400 TRACE(afu,
"AFU Index=%u", afu->identifier.afu_index);
401 TRACE(afu,
"AFU Version=%u:%u", afu->version_major, afu->version_minor);
402 TRACE(afu,
"Global MMIO size=%llu", afu->global_mmio.length);
403 TRACE(afu,
"Per PASID MMIO size=%llu", afu->per_pasid_mmio.length);
404 TRACE(afu,
"Page Size=%llu", afu->page_size);
405 TRACE(afu,
"PASID=%lu", afu->pasid);
418 static ocxl_err afu_open(ocxl_afu *afu)
426 int fd = open(afu->device_path, O_RDWR | O_CLOEXEC | O_NONBLOCK);
428 if (errno == ENOSPC) {
430 errmsg(afu, rc,
"Could not open AFU device '%s', the maximum number of contexts has been reached: Error %d: %s",
431 afu->device_path, errno, strerror(errno));
436 errmsg(afu, rc,
"Could not open AFU device '%s': Error %d: %s", afu->device_path, errno, strerror(errno));
444 errmsg(afu, rc,
"Could not open global MMIO descriptor");
448 fd = epoll_create1(EPOLL_CLOEXEC);
451 errmsg(afu, rc,
"Could not create epoll descriptor. Error %d: %s",
452 errno, strerror(errno));
457 struct epoll_event ev;
459 ev.data.ptr = &afu->fd_info;
460 if (epoll_ctl(afu->epoll_fd, EPOLL_CTL_ADD, afu->fd, &ev) == -1) {
462 errmsg(afu, rc,
"Could not add device fd %d to epoll fd %d: %d: '%s'",
463 afu->fd, afu->epoll_fd, errno, strerror(errno));
467 struct ocxl_ioctl_metadata metadata;
468 if (ioctl(afu->fd, OCXL_IOCTL_GET_METADATA, &metadata)) {
470 errmsg(afu, rc,
"OCXL_IOCTL_GET_METADATA failed %d:%s", errno, strerror(errno));
475 afu->version_major = metadata.afu_version_major;
476 afu->version_minor = metadata.afu_version_minor;
477 afu->per_pasid_mmio.length = metadata.pp_mmio_size;
478 afu->global_mmio.length = metadata.global_mmio_size;
479 afu->pasid = metadata.pasid;
507 ocxl_afu *my_afu = (ocxl_afu *) afu_h;
509 struct stat dev_stats;
510 if (stat(path, &dev_stats)) {
512 errmsg(NULL, rc,
"Could not stat AFU device '%s': Error %d: %s", path, errno, strerror(errno));
517 if (!populate_metadata(dev_stats.st_rdev, my_afu)) {
519 errmsg(NULL, rc,
"Could not find OCXL device for '%s', major=%d, minor=%d, device expected in '%s'",
520 path, major(dev_stats.st_rdev), minor(dev_stats.st_rdev), DEVICE_PATH);
543 ocxl_err rc = get_afu_by_path(path, afu);
550 rc = afu_open((ocxl_afu *)*afu);
575 char pattern[PATH_MAX];
580 if (afu_index == -1) {
581 snprintf(pattern,
sizeof(pattern),
"%s/%s.%s.*",
583 physical_function ? physical_function :
"*");
585 snprintf(pattern,
sizeof(pattern),
"%s/%s.%s.%d",
587 physical_function ? physical_function :
"*",
591 int rc = glob(pattern, GLOB_ERR, NULL, &glob_data);
597 errmsg(NULL, ret,
"No memory for glob while listing AFUs");
601 errmsg(NULL, ret,
"No OCXL devices found in '%s' with pattern '%s'", DEVICE_PATH, pattern);
604 errmsg(NULL, ret,
"Glob error %d while listing AFUs", rc);
608 for (
size_t dev = 0; dev < glob_data.gl_pathc; dev++) {
609 const char *dev_path = glob_data.gl_pathv[dev];
625 globfree(&glob_data);
665 ocxl_afu *my_afu = (ocxl_afu *) afu;
667 if (my_afu->fd == -1) {
669 errmsg(my_afu, rc,
"Attempted to attach a closed AFU context");
673 struct ocxl_ioctl_attach attach_args;
674 memset(&attach_args,
'\0',
sizeof(attach_args));
676 attach_args.amr = my_afu->ppc64_amr;
679 if (ioctl(my_afu->fd, OCXL_IOCTL_ATTACH, &attach_args)) {
681 errmsg(my_afu, rc,
"OCXL_IOCTL_ATTACH failed %d:%s", errno, strerror(errno));
703 ocxl_afu *my_afu = (ocxl_afu *) afu;
705 if (my_afu->fd < 0) {
709 for (uint16_t mmio_idx = 0; mmio_idx < my_afu->mmio_count; mmio_idx++) {
713 if (my_afu->global_mmio_fd) {
714 close(my_afu->global_mmio_fd);
715 my_afu->global_mmio_fd = -1;
719 for (uint16_t irq = 0; irq < my_afu->irq_count; irq++) {
725 my_afu->irq_count = 0;
726 my_afu->irq_max_count = 0;
729 if (my_afu->epoll_events) {
730 free(my_afu->epoll_events);
731 my_afu->epoll_event_count = 0;
734 close(my_afu->epoll_fd);
735 my_afu->epoll_fd = -1;
740 if (my_afu->device_path) {
741 free(my_afu->device_path);
742 my_afu->device_path = NULL;
745 if (my_afu->sysfs_path) {
746 free(my_afu->sysfs_path);
747 my_afu->sysfs_path = NULL;
781 ocxl_afu *my_afu = (ocxl_afu *) afu;
783 my_afu->ppc64_amr = amr;
ocxl_err ocxl_afu_set_ppc64_amr(ocxl_afu_h afu, uint64_t amr)
Set the PPC64-specific PSL AMR register value for restricting access to the AFU.
#define AFU_NAME_MAX
The maximum length of an AFU name.
const ocxl_identifier * ocxl_afu_get_identifier(ocxl_afu_h afu)
Get the identifier of the AFU.
ocxl_err
Potential return values from ocxl_* functions.
void irq_dealloc(ocxl_afu *afu, ocxl_irq *irq)
Deallocate a single IRQ.
ocxl_err ocxl_afu_attach(ocxl_afu_h afu, __attribute__((unused)) uint64_t flags)
Attach the calling process's memory to an open AFU context.
The call requires an open context on the AFU.
#define OCXL_ERRORS
Error messages requested.
void ocxl_mmio_unmap(ocxl_mmio_h region)
Unmap an MMIO region from an AFU.
uint32_t ocxl_afu_get_pasid(ocxl_afu_h afu)
Get the PASID for the currently open context.
void * ocxl_mmio_h
A handle for an MMIO region on an AFU.
an internal error has occurred
ocxl_err ocxl_afu_open(const char *name, ocxl_afu_h *afu)
Open an AFU context with a specified name.
const char * ocxl_afu_get_device_path(ocxl_afu_h afu)
Get the canonical device path of the AFU.
The OpenCAPI device is not available.
#define OCXL_INVALID_AFU
An invalid AFU handle.
void ocxl_afu_enable_messages(ocxl_afu_h afu, uint64_t sources)
Enable messages from an AFU.
AFU identification information.
ocxl_err ocxl_afu_open_from_dev(const char *path, ocxl_afu_h *afu)
Open an AFU context at a specified path.
void ocxl_afu_get_version(ocxl_afu_h afu, uint8_t *major, uint8_t *minor)
Get the version of the AFU.
const char * ocxl_afu_get_sysfs_path(ocxl_afu_h afu)
Get the canonical sysfs path of the AFU.
ocxl_err ocxl_afu_close(ocxl_afu_h afu)
Close an AFU and detach it from the context.
ocxl_err global_mmio_open(ocxl_afu *afu)
Open the global MMIO descriptor on an AFU.
void * ocxl_afu_h
A handle for an AFU.
An out of memory error occurred.
void ocxl_afu_set_error_message_handler(ocxl_afu_h afu, void(*handler)(ocxl_afu_h afu, ocxl_err error, const char *message))
Override the default handler for emitting error messages for an AFU.
#define OCXL_TRACING
Tracing requested.
No more contexts can be opened on the AFU.
The action requested has already been performed.
ocxl_err ocxl_afu_open_specific(const char *name, const char *physical_function, int16_t afu_index, ocxl_afu_h *afu)
Open an AFU context with a specified name on a specific card/afu index.