blob: 9af6adc1be6337a567e568f9c98c4e346e2f9961 [file]
/*
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <virtqueue.h>
#include <camkes/io.h>
#include "virtqueue_common.h"
struct vq_buf_alloc *init_vq_allocator(void *mem_pool, unsigned len, size_t block_size)
{
ps_malloc_ops_t malloc_ops;
int error = camkes_ps_malloc_ops(&malloc_ops);
if (error) {
return NULL;
}
struct vq_buf_alloc *allocator = NULL;
error = ps_calloc(&malloc_ops, 1, sizeof(*allocator), (void **)&allocator);
if (error) {
return NULL;
}
allocator->buffer = mem_pool;
allocator->len = len;
allocator->free_list_size = len / block_size;
allocator->block_size = block_size;
if (ps_calloc(&malloc_ops, 1, allocator->free_list_size * sizeof(*(allocator->free_list)),
(void **)(&allocator->free_list))) {
ZF_LOGE("Failed to allocate free_list");
ps_free(&malloc_ops, sizeof(*allocator), allocator);
return NULL;
}
unsigned i;
for (i = 0; i < allocator->free_list_size; i++) {
allocator->free_list[i] = i + 1;
}
allocator->head = 0;
return allocator;
}
int camkes_virtqueue_driver_init_common(virtqueue_driver_t *driver, volatile void *buffer, unsigned queue_len,
size_t buffer_size, void (*notify)(void), size_t block_size)
{
/* Don't check for notify, as it can be NULL in some situations */
if (!driver || !buffer) {
return EINVAL;
}
void *avail_ring = (void *) buffer;
void *used_ring = avail_ring + sizeof(vq_vring_avail_t) + sizeof(uint16_t) * queue_len;
void *desc = used_ring + sizeof(vq_vring_used_t) + sizeof(struct vq_vring_used_elem) * queue_len;
void *usable_buffer_start = desc + sizeof(vq_vring_desc_t) * queue_len;
unsigned usable_len = buffer_size - (sizeof(vq_vring_avail_t) + sizeof(vq_vring_used_t) +
sizeof(uint16_t) * queue_len + sizeof(struct vq_vring_used_elem) * queue_len +
sizeof(vq_vring_desc_t) * queue_len);
struct vq_buf_alloc *allocator = init_vq_allocator(usable_buffer_start, usable_len, block_size);
if (!allocator) {
return ENOMEM;
}
virtqueue_init_driver(driver, queue_len, avail_ring, used_ring, desc, notify, allocator);
return 0;
}
int camkes_virtqueue_device_init_common(virtqueue_device_t *device, volatile void *buffer, unsigned queue_len,
void (*notify)(void))
{
/* Don't check for notify, as it can be NULL in some situations */
if (!device || !buffer) {
return EINVAL;
}
void *avail_ring = (void *) buffer;
void *used_ring = avail_ring + sizeof(vq_vring_avail_t) + sizeof(uint16_t) * queue_len;
void *desc = used_ring + sizeof(vq_vring_used_t) + sizeof(struct vq_vring_used_elem) * queue_len;
void *cookie = desc + sizeof(vq_vring_desc_t) * queue_len;
virtqueue_init_device(device, queue_len, avail_ring, used_ring, desc, notify, cookie);
return 0;
}