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;
93 static ocxl_err irq_allocate(ocxl_afu *afu, ocxl_irq *irq,
void *info)
95 ocxl_afu *my_afu = (ocxl_afu *) afu;
97 irq->event.irq_offset = 0;
98 irq->event.eventfd = -1;
99 irq->event.reserved = 0;
100 irq->irq_number = UINT16_MAX;
103 irq->fd_info.type = EPOLL_SOURCE_IRQ;
104 irq->fd_info.irq = irq;
108 int fd = eventfd(0, EFD_CLOEXEC);
110 errmsg(afu, ret,
"Could not open eventfd : %d: '%s'", errno, strerror(errno));
113 irq->event.eventfd = fd;
115 int rc = ioctl(afu->fd, OCXL_IOCTL_IRQ_ALLOC, &irq->event.irq_offset);
117 errmsg(afu, ret,
"Could not allocate IRQ in kernel: %d", rc);
121 rc = ioctl(my_afu->fd, OCXL_IOCTL_IRQ_SET_FD, &irq->event);
123 errmsg(afu, ret,
"Could not set event descriptor in kernel: %d", rc);
127 irq->addr = mmap(NULL, afu->page_size, PROT_WRITE, MAP_SHARED,
128 my_afu->fd, irq->event.irq_offset);
129 if (irq->addr == MAP_FAILED) {
130 errmsg(afu, ret,
"mmap for IRQ failed: %d: '%s'", errno, strerror(errno));
134 struct epoll_event ev;
136 ev.data.ptr = &irq->fd_info;
137 if (epoll_ctl(my_afu->epoll_fd, EPOLL_CTL_ADD, irq->event.eventfd, &ev) == -1) {
138 errmsg(afu, ret,
"Could not add IRQ fd %d to epoll fd %d: %d: '%s'",
139 irq->event.eventfd, my_afu->epoll_fd, errno, strerror(errno));
168 ocxl_afu *my_afu = (ocxl_afu *) afu;
170 if (my_afu->irq_count == my_afu->irq_max_count) {
171 ocxl_err rc = grow_buffer(my_afu, (
void **)&my_afu->irqs, &my_afu->irq_max_count,
sizeof(ocxl_irq), INITIAL_IRQ_COUNT);
173 errmsg(my_afu, rc,
"Could not grow IRQ buffer");
178 ocxl_err rc = irq_allocate(my_afu, &my_afu->irqs[my_afu->irq_count], info);
180 errmsg(my_afu, rc,
"Could not allocate IRQ");
183 my_afu->irqs[my_afu->irq_count].irq_number = my_afu->irq_count;
203 ocxl_afu *my_afu = (ocxl_afu *) afu;
205 if (irq > my_afu->irq_count) {
209 return (uint64_t)my_afu->irqs[irq].addr;
224 ocxl_afu *my_afu = (ocxl_afu *) afu;
226 if (irq > my_afu->irq_count) {
230 return my_afu->irqs[irq].event.eventfd;
249 ocxl_afu *my_afu = (ocxl_afu *) afu;
265 static void populate_xsl_fault_error(ocxl_afu *afu,
ocxl_event *event,
void *body)
270 event->translation_fault.addr = (
void *)err->addr;
272 event->translation_fault.dsisr = err->dsisr;
273 TRACE(
"Translation fault error received, addr=%p, dsisr=%llx, count=%llu",
274 event->translation_fault.addr, event->translation_fault.dsisr, err->count);
276 TRACE(afu,
"Translation fault error received, addr=%p, count=%llu",
277 event->translation_fault.addr, err->count);
279 event->translation_fault.count = err->count;
315 static ocxl_event_action read_afu_event(
ocxl_afu_h afu, uint16_t event_api_version,
ocxl_event *event,
int *last)
317 ocxl_afu *my_afu = (ocxl_afu *) afu;
322 uint16_t max_supported_event = 0;
324 switch (event_api_version) {
327 max_supported_event = OCXL_AFU_EVENT_XSL_FAULT_ERROR;
330 errmsg(afu,
OCXL_INTERNAL_ERROR,
"Unsupported event API version %u, your libocxl library may be too old",
332 return OCXL_EVENT_ACTION_FAIL;
335 char buf[event_size];
338 if ((buf_used = read(my_afu->fd, buf, event_size)) < 0) {
339 if (errno == EAGAIN || errno == EWOULDBLOCK) {
341 return OCXL_EVENT_ACTION_NONE;
345 my_afu->fd, errno, strerror(errno));
346 return OCXL_EVENT_ACTION_FAIL;
349 return OCXL_EVENT_ACTION_FAIL;
354 if (header->type > max_supported_event) {
355 TRACE(my_afu,
"Unknown event received from kernel of type %u", header->type);
356 *last = !! (header->flags & OCXL_KERNEL_EVENT_FLAG_LAST);
357 return OCXL_EVENT_ACTION_IGNORE;
360 switch (header->type) {
361 case OCXL_AFU_EVENT_XSL_FAULT_ERROR:
364 "Incorrectly sized buffer received from kernel for XSL fault error, expected %d, got %d",
367 return OCXL_EVENT_ACTION_FAIL;
374 header->type, max_supported_event);
375 return OCXL_EVENT_ACTION_FAIL;
378 *last = !! (header->flags & OCXL_KERNEL_EVENT_FLAG_LAST);
379 return OCXL_EVENT_ACTION_SUCCESS;
408 uint16_t event_api_version)
410 ocxl_afu *my_afu = (ocxl_afu *) afu;
411 TRACE(my_afu,
"Waiting up to %dms for AFU events", timeout);
413 if (event_count > my_afu->epoll_event_count) {
414 free(my_afu->epoll_events);
415 my_afu->epoll_events = NULL;
416 my_afu->epoll_event_count = 0;
418 struct epoll_event *events = malloc(event_count *
sizeof(*events));
419 if (events == NULL) {
420 errmsg(my_afu,
OCXL_NO_MEM,
"Could not allocate space for %d events", event_count);
424 my_afu->epoll_events = events;
425 my_afu->epoll_event_count = event_count;
429 if ((count = epoll_wait(my_afu->epoll_fd, my_afu->epoll_events, event_count, timeout)) == -1) {
431 errno, strerror(errno));
435 uint16_t triggered = 0;
436 for (
int event = 0;
event < count;
event++) {
437 epoll_fd_source *info = (epoll_fd_source *)my_afu->epoll_events[event].data.ptr;
438 ocxl_event_action ret;
442 switch (info->type) {
443 case EPOLL_SOURCE_OCXL:
444 while ((ret = read_afu_event(my_afu, event_api_version, &events[triggered], &last)),
445 ret == OCXL_EVENT_ACTION_SUCCESS || ret == OCXL_EVENT_ACTION_IGNORE) {
446 if (ret == OCXL_EVENT_ACTION_SUCCESS) {
455 if (ret == OCXL_EVENT_ACTION_FAIL) {
461 case EPOLL_SOURCE_IRQ:
462 if (read(info->irq->event.eventfd, &count,
sizeof(count)) < 0) {
464 info->irq->event.eventfd, info->irq->irq_number, errno, strerror(errno));
468 events[triggered].irq.irq = info->irq->irq_number;
469 events[triggered].irq.handle = (uint64_t)info->irq->addr;
470 events[triggered].irq.info = info->irq->info;
471 events[triggered++].irq.count = count;
473 TRACE(my_afu,
"IRQ received, irq=%u id=%llx info=%p count=%llu",
474 info->irq->irq_number, (uint64_t)info->irq->addr, info->irq->info, count);
480 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