17 #include "libocxl_internal.h"
18 #include <sys/types.h>
20 #include <sys/select.h>
26 #include <sys/eventfd.h>
27 #include <misc/ocxl.h>
29 #include <sys/ioctl.h>
32 #include <sys/epoll.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;
92 static ocxl_err irq_allocate(ocxl_afu *afu, ocxl_irq *irq,
void *info)
94 ocxl_afu *my_afu = (ocxl_afu *) afu;
96 irq->event.irq_offset = 0;
97 irq->event.eventfd = -1;
98 irq->event.reserved = 0;
99 irq->irq_number = UINT16_MAX;
102 irq->fd_info.type = EPOLL_SOURCE_IRQ;
103 irq->fd_info.irq = irq;
107 int fd = eventfd(0, EFD_CLOEXEC);
109 errmsg(afu, ret,
"Could not open eventfd : %d: '%s'", errno, strerror(errno));
112 irq->event.eventfd = fd;
114 int rc = ioctl(afu->fd, OCXL_IOCTL_IRQ_ALLOC, &irq->event.irq_offset);
116 errmsg(afu, ret,
"Could not allocate IRQ in kernel: %d", rc);
120 rc = ioctl(my_afu->fd, OCXL_IOCTL_IRQ_SET_FD, &irq->event);
122 errmsg(afu, ret,
"Could not set event descriptor in kernel: %d", rc);
126 irq->addr = mmap(NULL, afu->page_size, PROT_WRITE, MAP_SHARED,
127 my_afu->fd, irq->event.irq_offset);
128 if (irq->addr == MAP_FAILED) {
129 errmsg(afu, ret,
"mmap for IRQ failed: %d: '%s'", errno, strerror(errno));
133 struct epoll_event ev;
135 ev.data.ptr = &irq->fd_info;
136 if (epoll_ctl(my_afu->epoll_fd, EPOLL_CTL_ADD, irq->event.eventfd, &ev) == -1) {
137 errmsg(afu, ret,
"Could not add IRQ fd %d to epoll fd %d: %d: '%s'",
138 irq->event.eventfd, my_afu->epoll_fd, errno, strerror(errno));
167 ocxl_afu *my_afu = (ocxl_afu *) afu;
169 if (my_afu->irq_count == my_afu->irq_max_count) {
170 ocxl_err rc = grow_buffer(my_afu, (
void **)&my_afu->irqs, &my_afu->irq_max_count,
sizeof(ocxl_irq), INITIAL_IRQ_COUNT);
172 errmsg(my_afu, rc,
"Could not grow IRQ buffer");
177 ocxl_err rc = irq_allocate(my_afu, &my_afu->irqs[my_afu->irq_count], info);
179 errmsg(my_afu, rc,
"Could not allocate IRQ");
182 my_afu->irqs[my_afu->irq_count].irq_number = my_afu->irq_count;
202 ocxl_afu *my_afu = (ocxl_afu *) afu;
204 if (irq > my_afu->irq_count) {
208 return (uint64_t)my_afu->irqs[irq].addr;
223 ocxl_afu *my_afu = (ocxl_afu *) afu;
225 if (irq > my_afu->irq_count) {
229 return my_afu->irqs[irq].event.eventfd;
248 ocxl_afu *my_afu = (ocxl_afu *) afu;
264 static void populate_xsl_fault_error(ocxl_afu *afu,
ocxl_event *event,
void *body)
269 event->translation_fault.addr = (
void *)err->addr;
271 event->translation_fault.dsisr = err->dsisr;
272 TRACE(afu,
"Translation fault error received, addr=%p, dsisr=%llx, count=%llu",
273 event->translation_fault.addr, event->translation_fault.dsisr, err->count);
275 TRACE(afu,
"Translation fault error received, addr=%p, count=%llu",
276 event->translation_fault.addr, err->count);
278 event->translation_fault.count = err->count;
314 static ocxl_event_action read_afu_event(
ocxl_afu_h afu, uint16_t event_api_version,
ocxl_event *event,
int *last)
316 ocxl_afu *my_afu = (ocxl_afu *) afu;
321 uint16_t max_supported_event = 0;
323 switch (event_api_version) {
326 max_supported_event = OCXL_AFU_EVENT_XSL_FAULT_ERROR;
329 errmsg(afu,
OCXL_INTERNAL_ERROR,
"Unsupported event API version %u, your libocxl library may be too old",
331 return OCXL_EVENT_ACTION_FAIL;
334 char buf[event_size];
337 if ((buf_used = read(my_afu->fd, buf, event_size)) < 0) {
338 if (errno == EAGAIN || errno == EWOULDBLOCK) {
340 return OCXL_EVENT_ACTION_NONE;
344 my_afu->fd, errno, strerror(errno));
345 return OCXL_EVENT_ACTION_FAIL;
348 return OCXL_EVENT_ACTION_FAIL;
353 if (header->type > max_supported_event) {
354 TRACE(my_afu,
"Unknown event received from kernel of type %u", header->type);
355 *last = !! (header->flags & OCXL_KERNEL_EVENT_FLAG_LAST);
356 return OCXL_EVENT_ACTION_IGNORE;
359 switch (header->type) {
360 case OCXL_AFU_EVENT_XSL_FAULT_ERROR:
363 "Incorrectly sized buffer received from kernel for XSL fault error, expected %d, got %d",
366 return OCXL_EVENT_ACTION_FAIL;
373 header->type, max_supported_event);
374 return OCXL_EVENT_ACTION_FAIL;
377 *last = !! (header->flags & OCXL_KERNEL_EVENT_FLAG_LAST);
378 return OCXL_EVENT_ACTION_SUCCESS;
407 uint16_t event_api_version)
409 ocxl_afu *my_afu = (ocxl_afu *) afu;
410 TRACE(my_afu,
"Waiting up to %dms for AFU events", timeout);
412 if (event_count > my_afu->epoll_event_count) {
413 free(my_afu->epoll_events);
414 my_afu->epoll_events = NULL;
415 my_afu->epoll_event_count = 0;
417 struct epoll_event *events = malloc(event_count *
sizeof(*events));
418 if (events == NULL) {
419 errmsg(my_afu,
OCXL_NO_MEM,
"Could not allocate space for %d events", event_count);
423 my_afu->epoll_events = events;
424 my_afu->epoll_event_count = event_count;
428 if ((count = epoll_wait(my_afu->epoll_fd, my_afu->epoll_events, event_count, timeout)) == -1) {
430 errno, strerror(errno));
434 uint16_t triggered = 0;
435 for (
int event = 0;
event < count;
event++) {
436 epoll_fd_source *info = (epoll_fd_source *)my_afu->epoll_events[event].data.ptr;
437 ocxl_event_action ret;
441 switch (info->type) {
442 case EPOLL_SOURCE_OCXL:
443 while ((ret = read_afu_event(my_afu, event_api_version, &events[triggered], &last)),
444 ret == OCXL_EVENT_ACTION_SUCCESS || ret == OCXL_EVENT_ACTION_IGNORE) {
445 if (ret == OCXL_EVENT_ACTION_SUCCESS) {
454 if (ret == OCXL_EVENT_ACTION_FAIL) {
460 case EPOLL_SOURCE_IRQ:
461 if (read(info->irq->event.eventfd, &count,
sizeof(count)) < 0) {
463 info->irq->event.eventfd, info->irq->irq_number, errno, strerror(errno));
467 events[triggered].irq.irq = info->irq->irq_number;
468 events[triggered].irq.handle = (uint64_t)info->irq->addr;
469 events[triggered].irq.info = info->irq->info;
470 events[triggered++].irq.count = count;
472 TRACE(my_afu,
"IRQ received, irq=%u id=%llx info=%p count=%llu",
473 info->irq->irq_number, (uint64_t)info->irq->addr, info->irq->info, count);
479 TRACE(my_afu,
"%u events reported", triggered);
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.
ocxl_err
Potential return values from ocxl_* functions.
uint16_t ocxl_irq_h
A handle for an IRQ on an AFU.
void irq_dealloc(ocxl_afu *afu, ocxl_irq *irq)
Deallocate a single IRQ.
an internal error has occurred
ocxl_err ocxl_irq_alloc(ocxl_afu_h afu, void *info, ocxl_irq_h *irq)
Allocate an IRQ for an open AFU.
A memory translation fault occurred on the AFU.
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_header ocxl_kernel_event_header
void * ocxl_afu_h
A handle for an AFU.
An out of memory error occurred.
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.
struct ocxl_kernel_event_xsl_fault_error ocxl_kernel_event_xsl_fault_error