17#include "libocxl_internal.h"
20#include <sys/select.h>
26#include <sys/eventfd.h>
34#define MAX_EVENT_SIZE (16*sizeof(uint64_t))
45 if (munmap(irq->addr, afu->page_size)) {
47 errno, strerror(errno));
52 if (irq->event.irq_offset) {
53 int rc = ioctl(afu->fd, OCXL_IOCTL_IRQ_FREE, &irq->event.irq_offset);
57 irq->event.irq_offset = 0;
60 if (irq->event.eventfd >= 0) {
61 close(irq->event.eventfd);
62 irq->event.eventfd = -1;
93static ocxl_err irq_allocate(ocxl_afu *afu, ocxl_irq *irq,
void *info)
95 irq->event.irq_offset = 0;
96 irq->event.eventfd = -1;
97 irq->event.reserved = 0;
98 irq->irq_number = UINT16_MAX;
101 irq->fd_info.type = EPOLL_SOURCE_IRQ;
102 irq->fd_info.irq = irq;
106 int fd = eventfd(0, EFD_CLOEXEC);
108 errmsg(afu, ret,
"Could not open eventfd : %d: '%s'", errno, strerror(errno));
111 irq->event.eventfd = fd;
113 int rc = ioctl(afu->fd, OCXL_IOCTL_IRQ_ALLOC, &irq->event.irq_offset);
115 errmsg(afu, ret,
"Could not allocate IRQ in kernel: %d: '%s'", errno, strerror(errno));
119 rc = ioctl(afu->fd, OCXL_IOCTL_IRQ_SET_FD, &irq->event);
121 errmsg(afu, ret,
"Could not set event descriptor in kernel: %d: '%s'", errno, strerror(errno));
125 irq->addr = mmap(NULL, afu->page_size, PROT_WRITE, MAP_SHARED,
126 afu->fd, irq->event.irq_offset);
127 if (irq->addr == MAP_FAILED) {
128 errmsg(afu, ret,
"mmap for IRQ failed: %d: '%s'", errno, strerror(errno));
132 struct epoll_event ev;
134 ev.data.ptr = &irq->fd_info;
135 if (epoll_ctl(afu->epoll_fd, EPOLL_CTL_ADD, irq->event.eventfd, &ev) == -1) {
136 errmsg(afu, ret,
"Could not add IRQ fd %d to epoll fd %d: %d: '%s'",
137 irq->event.eventfd, afu->epoll_fd, errno, strerror(errno));
166 if (afu->irq_count == afu->irq_max_count) {
167 ocxl_err rc = grow_buffer(afu, (
void **)&afu->irqs, &afu->irq_max_count,
sizeof(ocxl_irq), INITIAL_IRQ_COUNT);
169 errmsg(afu, rc,
"Could not grow IRQ buffer");
174 ocxl_err rc = irq_allocate(afu, &afu->irqs[afu->irq_count], info);
176 errmsg(afu, rc,
"Could not allocate IRQ");
179 afu->irqs[afu->irq_count].irq_number = afu->irq_count;
199 if (irq > afu->irq_count) {
203 return (uint64_t)afu->irqs[irq].addr;
218 if (irq > afu->irq_count) {
222 return afu->irqs[irq].event.eventfd;
255static void populate_xsl_fault_error(ocxl_afu *afu,
ocxl_event *event,
void *body)
260 event->translation_fault.addr = (
void *)err->addr;
262 event->translation_fault.dsisr = err->dsisr;
263 TRACE(afu,
"Translation fault error received, addr=%p, dsisr=%llx, count=%llu",
264 event->translation_fault.addr, event->translation_fault.dsisr, err->count);
266 TRACE(afu,
"Translation fault error received, addr=%p, count=%llu",
267 event->translation_fault.addr, err->count);
269 event->translation_fault.count = err->count;
305static ocxl_event_action read_afu_event(
ocxl_afu_h afu, uint16_t event_api_version,
ocxl_event *event,
int *last)
310 uint16_t max_supported_event = 0;
312 switch (event_api_version) {
315 max_supported_event = OCXL_AFU_EVENT_XSL_FAULT_ERROR;
318 errmsg(afu,
OCXL_INTERNAL_ERROR,
"Unsupported event API version %u, your libocxl library may be too old",
320 return OCXL_EVENT_ACTION_FAIL;
323 char buf[event_size];
326 if ((buf_used = read(afu->fd, buf, event_size)) < 0) {
327 if (errno == EAGAIN || errno == EWOULDBLOCK) {
329 return OCXL_EVENT_ACTION_NONE;
333 afu->fd, errno, strerror(errno));
334 return OCXL_EVENT_ACTION_FAIL;
337 return OCXL_EVENT_ACTION_FAIL;
342 if (header->type > max_supported_event) {
343 TRACE(afu,
"Unknown event received from kernel of type %u", header->type);
344 *last = !! (header->flags & OCXL_KERNEL_EVENT_FLAG_LAST);
345 return OCXL_EVENT_ACTION_IGNORE;
348 switch (header->type) {
349 case OCXL_AFU_EVENT_XSL_FAULT_ERROR:
352 "Incorrectly sized buffer received from kernel for XSL fault error, expected %d, got %d",
355 return OCXL_EVENT_ACTION_FAIL;
362 header->type, max_supported_event);
363 return OCXL_EVENT_ACTION_FAIL;
366 *last = !! (header->flags & OCXL_KERNEL_EVENT_FLAG_LAST);
367 return OCXL_EVENT_ACTION_SUCCESS;
396 uint16_t event_api_version)
398 TRACE(afu,
"Waiting up to %dms for AFU events", timeout);
400 if (event_count > afu->epoll_event_count) {
401 free(afu->epoll_events);
402 afu->epoll_events = NULL;
403 afu->epoll_event_count = 0;
405 struct epoll_event *events = malloc(event_count *
sizeof(*events));
406 if (events == NULL) {
407 errmsg(afu,
OCXL_NO_MEM,
"Could not allocate space for %d events", event_count);
411 afu->epoll_events = events;
412 afu->epoll_event_count = event_count;
416 if ((count = epoll_wait(afu->epoll_fd, afu->epoll_events, event_count, timeout)) == -1) {
418 errno, strerror(errno));
422 uint16_t triggered = 0;
423 for (
int event = 0;
event < count;
event++) {
424 epoll_fd_source *info = (epoll_fd_source *)afu->epoll_events[event].data.ptr;
425 ocxl_event_action ret;
430 switch (info->type) {
431 case EPOLL_SOURCE_OCXL:
432 while ((ret = read_afu_event(afu, event_api_version, &events[triggered], &last)),
433 ret == OCXL_EVENT_ACTION_SUCCESS || ret == OCXL_EVENT_ACTION_IGNORE) {
434 if (ret == OCXL_EVENT_ACTION_SUCCESS) {
443 if (ret == OCXL_EVENT_ACTION_FAIL) {
449 case EPOLL_SOURCE_IRQ:
450 buf_used = read(info->irq->event.eventfd, &count,
sizeof(count));
453 info->irq->event.eventfd, info->irq->irq_number, errno, strerror(errno));
455 }
else if (buf_used != (ssize_t)
sizeof(count)) {
460 events[triggered].irq.irq = info->irq->irq_number;
461 events[triggered].irq.handle = (uint64_t)info->irq->addr;
462 events[triggered].irq.info = info->irq->info;
463 events[triggered++].irq.count = count;
465 TRACE(afu,
"IRQ received, irq=%u id=%llx info=%p count=%llu",
466 info->irq->irq_number, (uint64_t)info->irq->addr, info->irq->info, count);
472 TRACE(afu,
"%u events reported", triggered);
499 ocxl_afu *my_afu = (ocxl_afu *)afu;
501 struct ocxl_ioctl_features features;
503 int rc = ioctl(my_afu->fd, OCXL_IOCTL_GET_FEATURES, &features);
505 errmsg(afu,
OCXL_NO_DEV,
"Could not identify platform: %d %s",
506 errno, strerror(errno));
510 if (!(features.flags[0] & OCXL_IOCTL_FEATURES_FLAGS0_P9_WAIT)) {
511 errmsg(afu,
OCXL_NO_DEV,
"Power 9 wait is not available on this machine");
515 struct ocxl_ioctl_p9_wait wait_data;
517 rc = ioctl(my_afu->fd, OCXL_IOCTL_ENABLE_P9_WAIT, &wait_data);
519 errmsg(afu,
OCXL_NO_DEV,
"Could not enable wait in kernel: %d %s",
520 errno, strerror(errno));
524 *thread_id = wait_data.thread_id;
int ocxl_afu_event_check_versioned(ocxl_afu_h afu, int timeout, ocxl_event *events, uint16_t event_count, uint16_t event_api_version)
Check for pending IRQs and other events.
ocxl_err ocxl_afu_get_p9_thread_id(ocxl_afu_h afu, uint16_t *thread_id)
Get the thread ID required to wake up a Power 9 wait instruction.
uint64_t ocxl_irq_get_handle(ocxl_afu_h afu, ocxl_irq_h irq)
Get the 64 bit IRQ handle for an IRQ.
struct ocxl_kernel_event_xsl_fault_error ocxl_kernel_event_xsl_fault_error
ocxl_err ocxl_irq_alloc(ocxl_afu_h afu, void *info, ocxl_irq_h *irq)
Allocate an IRQ for an open AFU.
int ocxl_irq_get_fd(ocxl_afu_h afu, ocxl_irq_h irq)
Get the file descriptor associated with an IRQ.
int ocxl_afu_get_event_fd(ocxl_afu_h afu)
Get a descriptor that will trigger a poll when an AFU event occurs.
struct ocxl_kernel_event_header ocxl_kernel_event_header
void irq_dealloc(ocxl_afu *afu, ocxl_irq *irq)
Deallocate a single IRQ.
ocxl_err
Potential return values from ocxl_* functions.
@ OCXL_NO_DEV
The OpenCAPI device is not available.
@ OCXL_INTERNAL_ERROR
an internal error has occurred
@ OCXL_OK
The call succeeded.
@ OCXL_NO_MEM
An out of memory error occurred.
struct ocxl_afu * ocxl_afu_h
A handle for an AFU.
uint16_t ocxl_irq_h
A handle for an IRQ on an AFU.
@ OCXL_EVENT_TRANSLATION_FAULT
A memory translation fault occurred on the AFU.
@ OCXL_EVENT_IRQ
An AFU IRQ.