17 #include "libocxl_internal.h" 20 #include <sys/types.h> 54 int available_mmio = -1;
57 for (uint16_t mmio = 0; mmio < afu->mmio_count; mmio++) {
58 if (!afu->mmios[mmio].start) {
59 available_mmio = mmio;
64 if (available_mmio == -1) {
65 if (afu->mmio_count == afu->mmio_max_count) {
66 ocxl_err rc = grow_buffer(afu, (
void **)&afu->mmios, &afu->mmio_max_count,
sizeof(ocxl_mmio_area), INITIAL_MMIO_COUNT);
68 errmsg(afu, rc,
"Could not grow MMIO buffer");
73 available_mmio = afu->mmio_count++;
76 afu->mmios[available_mmio].start = addr;
77 afu->mmios[available_mmio].length = size;
78 afu->mmios[available_mmio].type = type;
79 afu->mmios[available_mmio].afu = afu;
83 TRACE(afu,
"Mapped %ld bytes of %s MMIO at %p",
98 char path[PATH_MAX + 1];
99 int length = snprintf(path,
sizeof(path),
"%s/global_mmio_area", afu->sysfs_path);
100 if (length >= (
int)
sizeof(path)) {
102 errmsg(afu, rc,
"global MMIO path truncated");
106 int fd = open(path, O_RDWR | O_CLOEXEC);
109 errmsg(afu, rc,
"Could not open global MMIO '%s': Error %d: %s", path, errno, strerror(errno));
113 afu->global_mmio_fd = fd;
141 static ocxl_err global_mmio_map(ocxl_afu *afu,
size_t size,
int prot, uint64_t flags, off_t offset,
144 if (afu->global_mmio.length == 0) {
146 errmsg(afu, rc,
"Cannot map Global MMIO as there is 0 bytes allocated by the AFU");
152 errmsg(afu, rc,
"MMIO flags of 0x%llx is not supported by this version of libocxl", flags);
157 size = afu->global_mmio.length;
160 void *addr = mmap(NULL, size, prot, MAP_SHARED, afu->global_mmio_fd, offset);
161 if (addr == MAP_FAILED) {
163 errmsg(afu, rc,
"Could not map global MMIO, %d: %s", errno, strerror(errno));
170 errmsg(afu, rc,
"Could not register global MMIO region");
174 *region = mmio_region;
202 static ocxl_err mmio_map(ocxl_afu *afu,
size_t size,
int prot, uint64_t flags, off_t offset,
ocxl_mmio_h *region)
206 errmsg(afu, rc,
"MMIO flags of 0x%llx is not supported by this version of libocxl", flags);
212 errmsg(afu, rc,
"Could not map per-PASID MMIO as the AFU has not been opened");
216 if (!afu->attached) {
218 errmsg(afu, rc,
"Could not map per-PASID MMIO as the AFU has not been attached");
222 void *addr = mmap(NULL, size, prot, MAP_SHARED, afu->fd, offset);
223 if (addr == MAP_FAILED) {
225 errmsg(afu, rc,
"Could not map per-PASID MMIO: %d: %s", errno, strerror(errno));
232 errmsg(afu, rc,
"Could not register global MMIO region", afu->identifier.afu_name);
236 *region = mmio_region;
265 ocxl_afu *my_afu = (ocxl_afu *) afu;
271 size = my_afu->per_pasid_mmio.length;
274 size = my_afu->global_mmio.length;
281 if (offset + size > my_afu->global_mmio.length) {
283 errmsg(my_afu, rc,
"Offset(%x) + size(%x) of global MMIO map request exceeds available size of %x",
284 offset, size, my_afu->global_mmio.length);
287 return global_mmio_map(my_afu, size, prot, flags, offset, region);
291 if (offset + size > my_afu->global_mmio.length) {
293 errmsg(my_afu, rc,
"Offset(%x) + size(%x) of global MMIO map request exceeds available size of %x",
294 offset, size, my_afu->global_mmio.length);
297 return mmio_map(my_afu, size, prot, flags, offset, region);
301 errmsg(my_afu, rc,
"Unknown MMIO type %d", type);
338 ocxl_mmio_area *mmio = (ocxl_mmio_area *)region;
344 munmap(mmio->start, mmio->length);
364 ocxl_afu *my_afu = (ocxl_afu *) afu;
368 return my_afu->global_mmio_fd;
391 ocxl_afu *my_afu = (ocxl_afu *) afu;
395 return my_afu->global_mmio.length;
398 return my_afu->per_pasid_mmio.length;
421 ocxl_mmio_area *mmio = (ocxl_mmio_area *)region;
425 errmsg(mmio->afu, rc,
"MMIO region has already been unmapped");
429 *address = mmio->start;
430 *size = mmio->length;
451 errmsg(NULL, rc,
"MMIO region is invalid");
455 ocxl_mmio_area *mmio = (ocxl_mmio_area *)region;
459 errmsg(mmio->afu, rc,
"MMIO region has already been unmapped");
463 if (offset >= (off_t)(mmio->length - (size - 1))) {
465 errmsg(mmio->afu, rc,
"%s MMIO access of 0x%016lx exceeds limit of 0x%016lx",
467 offset, mmio->length);
494 ocxl_err ret = mmio_check(region, offset, 4);
499 ocxl_mmio_area *mmio = (ocxl_mmio_area *)region;
501 __sync_synchronize();
502 *out = *(
volatile uint32_t *)(mmio->start + offset);
503 __sync_synchronize();
505 TRACE(mmio->afu,
"%s MMIO Read32@0x%04lx=0x%08x",
532 ocxl_err ret = mmio_check(region, offset, 8);
537 ocxl_mmio_area *mmio = (ocxl_mmio_area *)region;
539 __sync_synchronize();
540 *out = *(
volatile uint64_t *)(mmio->start + offset);
541 __sync_synchronize();
543 TRACE(mmio->afu,
"%s MMIO Read64@0x%04lx=0x%016lx",
570 inline static ocxl_err mmio_write32_native(
ocxl_mmio_h region, off_t offset, uint32_t value)
572 ocxl_err ret = mmio_check(region, offset, 4);
577 ocxl_mmio_area *mmio = (ocxl_mmio_area *)region;
579 TRACE(mmio->afu,
"%s MMIO Write32@0x%04lx=0x%08x",
583 volatile uint32_t *addr = (uint32_t *)(mmio->start + offset);
585 __sync_synchronize();
587 __sync_synchronize();
610 inline static ocxl_err mmio_write64_native(
ocxl_mmio_h region, off_t offset, uint64_t value)
612 ocxl_err ret = mmio_check(region, offset, 8);
617 ocxl_mmio_area *mmio = (ocxl_mmio_area *)region;
619 TRACE(mmio->afu,
"%s MMIO Write64@0x%04lx=0x%016lx",
623 volatile uint64_t *addr = (uint64_t *)(mmio->start + offset);
625 __sync_synchronize();
627 __sync_synchronize();
653 ocxl_err ret = mmio_read32_native(mmio, offset, &val);
655 if (UNLIKELY(ret !=
OCXL_OK)) {
697 ocxl_err ret = mmio_read64_native(mmio, offset, &val);
699 if (UNLIKELY(ret !=
OCXL_OK)) {
742 value = htobe32(value);
746 value = htole32(value);
752 return mmio_write32_native(mmio, offset, value);
777 value = htobe64(value);
781 value = htole64(value);
787 return mmio_write64_native(mmio, offset, value);
AFU data is little-endian.
ocxl_err ocxl_mmio_map_advanced(ocxl_afu_h afu, ocxl_mmio_type type, size_t size, int prot, uint64_t flags, off_t offset, ocxl_mmio_h *region)
Map an MMIO area of an AFU.
ocxl_err ocxl_mmio_read32(ocxl_mmio_h mmio, off_t offset, ocxl_endian endian, uint32_t *out)
Read a 32-bit value from an AFU's MMIO region & convert endianess.
ocxl_err ocxl_mmio_get_info(ocxl_mmio_h region, void **address, size_t *size)
Get the address & size of a mapped MMIO region.
ocxl_err
Potential return values from ocxl_* functions.
size_t ocxl_mmio_size(ocxl_afu_h afu, ocxl_mmio_type type)
Get the size of an MMIO region for an AFU.
The action requested falls outside the permitted area.
The call requires an open context on the AFU.
ocxl_err ocxl_mmio_read64(ocxl_mmio_h mmio, off_t offset, ocxl_endian endian, uint64_t *out)
Read a 64-bit value from an AFU's MMIO region & convert endianess.
void ocxl_mmio_unmap(ocxl_mmio_h region)
Unmap an MMIO region from an AFU.
ocxl_err ocxl_mmio_map(ocxl_afu_h afu, ocxl_mmio_type type, ocxl_mmio_h *region)
Map an MMIO area of an AFU.
void * ocxl_mmio_h
A handle for an MMIO region on an AFU.
One or more arguments are invalid.
ocxl_endian
Defines the endianess of an AFU MMIO area.
The OpenCAPI device is not available.
ocxl_mmio_type
Defines the type of an MMIO area.
ocxl_err ocxl_mmio_write32(ocxl_mmio_h mmio, off_t offset, ocxl_endian endian, uint32_t value)
Convert endianess and write a 32-bit value to an AFU's MMIO region.
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.
ocxl_err ocxl_mmio_write64(ocxl_mmio_h mmio, off_t offset, ocxl_endian endian, uint64_t value)
Convert endianess and write a 64-bit value to an AFU's MMIO region.
int ocxl_mmio_get_fd(ocxl_afu_h afu, ocxl_mmio_type type)
Get a file descriptor for an MMIO area of an AFU.