Skip to content

Commit

Permalink
[Feature] - Add support for multi-port AFUs in OPAE vfio plugin
Browse files Browse the repository at this point in the history
Multi-port AFUs connect to more than one device from a single process, sharing
IOVA space across all devices.
  • Loading branch information
michael-adler committed Jan 19, 2024
1 parent 9ba83ec commit 4c75efc
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 3 deletions.
6 changes: 6 additions & 0 deletions include/opae/access.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ extern "C" {
* when all associated handles have been closed
* (either explicitly with fpgaClose() or by process
* termination).
* * FPGA_OPEN_HAS_PARENT_AFU is currently supported only
* inside OPAE, between the shell and a plugin. It
* indicates that the resource being opened is a child
* of a parent resource that is already open in the
* same process. When set, the value of *handle on
* entry is the parent handle.
* @returns FPGA_OK on success. FPGA_NOT_FOUND if the resource for
* 'token' could not be found. FPGA_INVALID_PARAM if
* 'token' does not refer to a resource that can be
Expand Down
4 changes: 3 additions & 1 deletion include/opae/types_enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,9 @@ enum fpga_buffer_flags {
*/
enum fpga_open_flags {
/** Open FPGA resource for shared access */
FPGA_OPEN_SHARED = (1u << 0)
FPGA_OPEN_SHARED = (1u << 0),
/** FPGA resource being opened has a parent in the same address space */
FPGA_OPEN_HAS_PARENT_AFU = (1u << 1)
};

/**
Expand Down
53 changes: 53 additions & 0 deletions include/opae/vfio.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,24 @@ int opae_vfio_secure_open(struct opae_vfio *v,
const char *pciaddr,
const char *token);

/**
* Note a new contraint on the group's IOVA space.
*
* OPAE does not yet attempt to connect multiple groups to the same vfio
* container. When multiple groups and containers are active in the same
* process, OPAE instead treats one container as the parent and applies
* the IOVA contraints of all other containers to the parent. This way,
* an IOVA choice in the parent is guaranteed legal in all groups.
* For now, the IOMMU has to be configured for each device but the
* same IOVA can be used because of the constraint managed here.
*
* @param[in] new_v New source of IOVA constraints.
* @param[in] v Apply constraints to this container.
* @returns Non-zero on error. Zero on success.
*/
int opae_vfio_apply_group_constraint(struct opae_vfio *new_v,
struct opae_vfio *v);

/**
* Query device MMIO region
*
Expand Down Expand Up @@ -447,6 +465,41 @@ struct opae_vfio_buffer *opae_vfio_buffer_info(struct opae_vfio *v,
int opae_vfio_buffer_free(struct opae_vfio *v,
uint8_t *buf);

/**
* Map an existing buffer for DMA at iova.
*
* Similar to opae_vfio_buffer_allocate_ex(), except that the
* iova is chosen by the caller and the buffer must already
* be allocated. The OPAE vfio library does not track the
* iova. It is the caller's responsibility to ensure the iova
* does not conflict. The caller is also responsible for
* unmapping with opae_vfio_buffer_unmap().
*
* @param[in, out] v The open OPAE VFIO device.
* @param[in] size Buffer size.
* @param[out] buf Buffer address.
* @param[out] iova IOVA at which buffer should be mapped.
* @returns Non-zero on error. Zero on success.
*/
int opae_vfio_buffer_map(struct opae_vfio *v,
size_t size,
uint8_t *buf,
uint64_t iova);

/**
* Unmap an existing pinned DMA page.
*
* Undo the effects of opae_vfio_buffer_map().
*
* @param[in, out] v The open OPAE VFIO device.
* @param[in] size Buffer size.
* @param[out] iova IOVA at which buffer should be pinned.
* @returns Non-zero on error. Zero on success.
*/
int opae_vfio_buffer_unmap(struct opae_vfio *v,
size_t size,
uint64_t iova);

/**
* Enable an IRQ
*
Expand Down
5 changes: 5 additions & 0 deletions libraries/libopae-c/api-shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,11 @@ fpga_result __OPAE_API__ fpgaOpen(fpga_token token, fpga_handle *handle,
ASSERT_NOT_NULL_RESULT(wrapped_token->adapter_table->fpgaClose,
FPGA_NOT_SUPPORTED);

if (flags & FPGA_OPEN_HAS_PARENT_AFU) {
ASSERT_NOT_NULL(*handle);
opae_handle = *handle;
}

res = wrapped_token->adapter_table->fpgaOpen(wrapped_token->opae_token,
&opae_handle, flags);

Expand Down
4 changes: 2 additions & 2 deletions libraries/libopae-c/multi-port-afu.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ fpga_result afu_open_children(opae_wrapped_handle *wrapped_parent_handle)
return FPGA_NOT_FOUND;
}

fpga_handle child_handle;
result = fpgaOpen(accel_token, &child_handle, 0);
fpga_handle child_handle = handle;
result = fpgaOpen(accel_token, &child_handle, FPGA_OPEN_HAS_PARENT_AFU);
fpgaDestroyToken(&accel_token);
if (result != FPGA_OK)
return result;
Expand Down
42 changes: 42 additions & 0 deletions libraries/libopaevfio/opaevfio.c
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,37 @@ int opae_vfio_buffer_free(struct opae_vfio *v,
return res;
}

int opae_vfio_buffer_map(struct opae_vfio *v,
size_t size,
uint8_t *buf,
uint64_t iova)
{
struct vfio_iommu_type1_dma_map dma_map;
memset(&dma_map, 0, sizeof(dma_map));

dma_map.argsz = sizeof(dma_map);
dma_map.vaddr = (uint64_t) buf;
dma_map.size = size;
dma_map.iova = iova;
dma_map.flags = VFIO_DMA_MAP_FLAG_READ|VFIO_DMA_MAP_FLAG_WRITE;

return opae_ioctl(v->cont_fd, VFIO_IOMMU_MAP_DMA, &dma_map);
}

int opae_vfio_buffer_unmap(struct opae_vfio *v,
size_t size,
uint64_t iova)
{
struct vfio_iommu_type1_dma_unmap dma_unmap;
memset(&dma_unmap, 0, sizeof(dma_unmap));

dma_unmap.argsz = sizeof(dma_unmap);
dma_unmap.size = size;
dma_unmap.iova = iova;

return opae_ioctl(v->cont_fd, VFIO_IOMMU_UNMAP_DMA, &dma_unmap);
}

STATIC int
opae_vfio_device_set_irqs(struct opae_vfio *v,
uint32_t index,
Expand Down Expand Up @@ -1296,6 +1327,17 @@ int opae_vfio_secure_open(struct opae_vfio *v,
return opae_vfio_init(v, pciaddr, token);
}

int opae_vfio_apply_group_constraint(struct opae_vfio *new_v,
struct opae_vfio *v)
{
if (!new_v || !v) {
ERR("NULL param\n");
return 1;
}

return 0;
}

int opae_vfio_region_get(struct opae_vfio *v,
uint32_t index,
uint8_t **ptr,
Expand Down
69 changes: 69 additions & 0 deletions libraries/plugins/vfio/opae_vfio.c
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,8 @@ fpga_result __VFIO_API__ vfio_fpgaOpen(fpga_token token, fpga_handle *handle, in

_handle->magic = VFIO_HANDLE_MAGIC;
_handle->token = clone_token(_token);
if (flags & FPGA_OPEN_HAS_PARENT_AFU)
_handle->parent_afu = handle_check_and_lock(*handle);

res = open_vfio_pair(_token->device->addr, &_handle->vfio_pair);
if (res) {
Expand Down Expand Up @@ -726,9 +728,21 @@ fpga_result __VFIO_API__ vfio_fpgaOpen(fpga_token token, fpga_handle *handle, in
#endif // GCC_VERSION
#endif // x86

if (_handle->parent_afu) {
if (opae_vfio_apply_group_constraint(
_handle->vfio_pair->device,
_handle->parent_afu->vfio_pair->device)) {
OPAE_ERR("error applying child vfio constraints");
res = FPGA_EXCEPTION;
goto out_attr_destroy;
}
}

*handle = _handle;
res = FPGA_OK;
out_attr_destroy:
if (_handle && _handle->parent_afu)
pthread_mutex_unlock(&_handle->parent_afu->lock);
pthread_mutexattr_destroy(&mattr);
if (res && _handle) {
pthread_mutex_destroy(&_handle->lock);
Expand Down Expand Up @@ -1656,6 +1670,61 @@ fpga_result __VFIO_API__ vfio_fpgaBindSVA(fpga_handle handle, uint32_t *pasid)
return res;
}

fpga_result __VFIO_API__ vfio_fpgaPinBuffer(fpga_handle handle, void *buf_addr,
uint64_t len, uint64_t ioaddr)
{
vfio_handle *h;
h = handle_check(handle);
ASSERT_NOT_NULL(h);

struct opae_vfio *v = h->vfio_pair->device;
if (opae_vfio_buffer_map(v, len, buf_addr, ioaddr)) {
OPAE_DBG("could not map buffer");
return FPGA_EXCEPTION;
}

return FPGA_OK;
}

fpga_result __VFIO_API__ vfio_fpgaUnpinBuffer(fpga_handle handle, void *buf_addr,
uint64_t len, uint64_t ioaddr)
{
UNUSED_PARAM(buf_addr);

vfio_handle *h;
h = handle_check(handle);
ASSERT_NOT_NULL(h);

struct opae_vfio *v = h->vfio_pair->device;
if (opae_vfio_buffer_unmap(v, len, ioaddr)) {
OPAE_DBG("could not unmap buffer");
return FPGA_EXCEPTION;
}

return FPGA_OK;
}

fpga_result __VFIO_API__ vfio_fpgaGetWSInfo(fpga_handle handle, uint64_t wsid,
uint64_t *ioaddr,
void **buf_addr, uint64_t *len)
{
UNUSED_PARAM(handle);

ASSERT_NOT_NULL(ioaddr);
ASSERT_NOT_NULL(buf_addr);
ASSERT_NOT_NULL(len);

struct opae_vfio_buffer *binfo = (struct opae_vfio_buffer *)wsid;

ASSERT_NOT_NULL(binfo);

*ioaddr = binfo->buffer_iova;
*buf_addr = (void *) binfo->buffer_ptr;
*len = binfo->buffer_size;

return FPGA_OK;
}

fpga_result __VFIO_API__ vfio_fpgaCreateEventHandle(fpga_event_handle *event_handle)
{
vfio_event_handle *_veh;
Expand Down
1 change: 1 addition & 0 deletions libraries/plugins/vfio/opae_vfio.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ typedef struct _vfio_pair {
typedef struct _vfio_handle {
uint32_t magic;
vfio_token *token;
struct _vfio_handle *parent_afu;
vfio_pair_t *vfio_pair;
volatile uint8_t *mmio_base;
size_t mmio_size;
Expand Down
6 changes: 6 additions & 0 deletions libraries/plugins/vfio/plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ int __VFIO_API__ opae_plugin_configure(opae_api_adapter_table *adapter,
dlsym(adapter->plugin.dl_handle, "vfio_fpgaGetIOAddress");
adapter->fpgaBindSVA =
dlsym(adapter->plugin.dl_handle, "vfio_fpgaBindSVA");
adapter->fpgaPinBuffer =
dlsym(adapter->plugin.dl_handle, "vfio_fpgaPinBuffer");
adapter->fpgaUnpinBuffer =
dlsym(adapter->plugin.dl_handle, "vfio_fpgaUnpinBuffer");
adapter->fpgaGetWSInfo =
dlsym(adapter->plugin.dl_handle, "vfio_fpgaGetWSInfo");
adapter->fpgaCreateEventHandle =
dlsym(adapter->plugin.dl_handle, "vfio_fpgaCreateEventHandle");
adapter->fpgaDestroyEventHandle =
Expand Down

0 comments on commit 4c75efc

Please sign in to comment.