diff --git a/lib/common/hil.c b/lib/common/hil.c
index 724040686c76b87cdd2846c3184995d09facd8d4..f832d6b7aab82899d2b7f1171d8e033840fde293 100644 (file)
--- a/lib/common/hil.c
+++ b/lib/common/hil.c
**************************************************************************/
#include "openamp/hil.h"
-#include "metal/utilities.h"
+#include "openamp/remoteproc.h"
+#include <metal/io.h>
+#include <metal/alloc.h>
+#include <metal/device.h>
+#include <metal/shmem.h>
+#include <metal/utilities.h>
+#include <metal/time.h>
+
+#define DEFAULT_VRING_MEM_SIZE 0x10000
/*--------------------------- Globals ---------------------------------- */
static METAL_DECLARE_LIST (procs);
#endif
-/**
- * hil_create_proc
- *
- * This function creates a HIL proc instance for given CPU id and populates
- * it with platform info.
- *
- * @param pdata - platform data for the remote processor
- * @param cpu_id - cpu id
- *
- * @return - pointer to proc instance
- *
- */
-struct hil_proc *hil_create_proc(void *pdata, int cpu_id)
+metal_phys_addr_t hil_generic_start_paddr = 0;
+struct metal_io_region hil_shm_generic_io = {
+ 0,
+ &hil_generic_start_paddr,
+ (size_t)(-1),
+ (sizeof(metal_phys_addr_t) << 3),
+ (metal_phys_addr_t)(-1),
+ 0,
+ {NULL},
+};
+
+struct metal_io_region hil_devmem_generic_io = {
+ 0,
+ &hil_generic_start_paddr,
+ (size_t)(-1),
+ (sizeof(metal_phys_addr_t) << 3),
+ (metal_phys_addr_t)(-1),
+ METAL_UNCACHED | METAL_SHARED_MEM,
+ {NULL},
+};
+
+struct hil_proc *hil_create_proc(struct hil_platform_ops *ops,
+ unsigned long cpu_id, void *pdata)
{
- struct hil_proc *proc, *proc_data;
- struct metal_list *node;
- int status;
-
- /* If proc already exists then return it */
- metal_list_for_each(&procs, node) {
- proc = metal_container_of(node, struct hil_proc, node);
- if (proc->cpu_id == (unsigned int)cpu_id) {
- return proc;
- }
- }
+ struct hil_proc *proc = 0;
+ int i;
- if (!pdata)
- return NULL;
- proc_data = (struct hil_proc *)pdata;
- if (!proc_data->ops || !proc_data->ops->initialize)
+ proc = metal_allocate_memory(sizeof(struct hil_proc));
+ if (!proc)
return NULL;
+ memset(proc, 0, sizeof(struct hil_proc));
- /* Allocate memory for proc instance */
- proc = env_allocate_memory(sizeof(struct hil_proc));
- if (!proc) {
- return NULL;
- }
-
- /* Get HW specfic info */
- status = proc_data->ops->initialize(pdata,
- proc, cpu_id);
- if (status) {
- env_free_memory(proc);
- return NULL;
- }
+ proc->ops = ops;
+ proc->num_chnls = 1;
+ proc->cpu_id = cpu_id;
+ proc->pdata = pdata;
- /* Enable mapping for the shared memory region */
- env_map_memory((unsigned int)proc->sh_buff.start_addr,
- (unsigned int)proc->sh_buff.start_addr,
- proc->sh_buff.size, (SHARED_MEM | UNCACHED));
+ /* Setup generic shared memory I/O region */
+ proc->sh_buff.io = &hil_shm_generic_io;
+ /* Setup generic vrings I/O region */
+ for (i = 0; i < HIL_MAX_NUM_VRINGS; i++)
+ proc->vdev.vring_info[i].io = &hil_devmem_generic_io;
+ metal_mutex_init(&proc->lock);
metal_list_add_tail(&procs, &proc->node);
return proc;
void hil_delete_proc(struct hil_proc *proc)
{
struct metal_list *node;
+ struct metal_device *dev;
+ struct metal_io_region *io;
+ struct proc_vring *vring;
+ int i;
metal_list_for_each(&procs, node) {
if (proc ==
metal_container_of(node, struct hil_proc, node)) {
metal_list_del(&proc->node);
+ metal_mutex_acquire(&proc->lock);
proc->ops->release(proc);
+ /* Close shmem device */
+ dev = proc->sh_buff.dev;
+ io = proc->sh_buff.io;
+ if (dev) {
+ metal_device_close(dev);
+ } else if (io && io->ops.close) {
+ io->ops.close(io);
+ }
+
+ /* Close vring device */
+ for (i = 0; i < HIL_MAX_NUM_VRINGS; i++) {
+ vring = &proc->vdev.vring_info[i];
+ dev = vring->dev;
+ io = vring->io;
+ if (dev) {
+ metal_device_close(dev);
+ } if (io && io->ops.close) {
+ io->ops.close(io);
+ }
+ }
+
+ metal_mutex_release(&proc->lock);
+ metal_mutex_deinit(&proc->lock);
+ metal_free_memory(proc);
return;
}
}
}
-/**
- * hil_isr()
- *
- * This function is called when interrupt is received for the vring.
- * This function gets the corresponding virtqueue and generates
- * call back for it.
- *
- * @param vring_hw - pointer to vring control block
- *
- */
-void hil_isr(struct proc_vring *vring_hw)
+int hil_init_proc(struct hil_proc *proc)
{
- virtqueue_notification(vring_hw->vq);
-}
-
-/**
- * hil_get_proc
- *
- * This function finds the proc instance based on the given ID
- * from the proc list and returns it to user.
- *
- * @param cpu_id - cpu id
- *
- * @return - pointer to hil proc instance
- *
- */
-struct hil_proc *hil_get_proc(int cpu_id)
-{
- struct metal_list *node;
- struct hil_proc *proc;
-
- metal_list_for_each(&procs, node) {
- proc = metal_container_of(node, struct hil_proc, node);
- if (proc->cpu_id == (unsigned int)cpu_id) {
- return proc;
- }
+ int ret = 0;
+ if (!proc->is_initialized && proc->ops->initialize) {
+ ret = proc->ops->initialize(proc);
+ if (!ret)
+ proc->is_initialized = 1;
+ else
+ return -1;
}
-
- return NULL;
+ return 0;
}
/**
return (proc->chnls);
}
+void hil_notified(struct hil_proc *proc, uint32_t notifyid)
+{
+ struct proc_vdev *pvdev = &proc->vdev;
+ struct fw_rsc_vdev *vdev_rsc = pvdev->vdev_info;
+ int i;
+ if (vdev_rsc->status & VIRTIO_CONFIG_STATUS_NEEDS_RESET) {
+ if (pvdev->rst_cb)
+ pvdev->rst_cb(proc, 0);
+ } else {
+ for(i = 0; i < (int)pvdev->num_vrings; i++) {
+ struct fw_rsc_vdev_vring *vring_rsc;
+ vring_rsc = &vdev_rsc->vring[i];
+ if (notifyid == (uint32_t)(-1) ||
+ notifyid == vring_rsc->notifyid)
+ virtqueue_notification(
+ pvdev->vring_info[i].vq);
+ }
+ }
+}
+
/**
* hil_get_vdev_info
*
*/
struct proc_vring *hil_get_vring_info(struct proc_vdev *vdev, int *num_vrings)
{
-
+ struct fw_rsc_vdev *vdev_rsc;
+ struct fw_rsc_vdev_vring *vring_rsc;
+ struct proc_vring *vring;
+ int i;
+
+ vdev_rsc = vdev->vdev_info;
+ if (vdev_rsc) {
+ vring = &vdev->vring_info[0];
+ for (i = 0; i < vdev_rsc->num_of_vrings; i++) {
+ /* Initialize vring with vring resource */
+ vring_rsc = &vdev_rsc->vring[i];
+ vring[i].num_descs = vring_rsc->num;
+ vring[i].align = vring_rsc->align;
+ /* Enable acccess to vring memory region */
+ vring[i].vaddr =
+ metal_io_mem_map(
+ (metal_phys_addr_t)vring_rsc->da,
+ vring[i].io,
+ vring_size(vring_rsc->num,
+ vring_rsc->align));
+ }
+ }
*num_vrings = vdev->num_vrings;
return (vdev->vring_info);
return (&proc->sh_buff);
}
+void hil_free_vqs(struct virtio_device *vdev)
+{
+ struct hil_proc *proc = vdev->device;
+ struct proc_vdev *pvdev = &proc->vdev;
+ int num_vrings = (int)pvdev->num_vrings;
+ int i;
+
+ metal_mutex_acquire(&proc->lock);
+ for(i = 0; i < num_vrings; i++) {
+ struct proc_vring *pvring = &pvdev->vring_info[i];
+ struct virtqueue *vq = pvring->vq;
+ if (vq) {
+ virtqueue_free(vq);
+ pvring->vq = 0;
+ }
+ }
+ metal_mutex_release(&proc->lock);
+}
+
+int hil_enable_vdev_notification(struct hil_proc *proc, int id)
+{
+ /* We only support single vdev in hil_proc */
+ (void)id;
+ if (!proc)
+ return -1;
+ if (proc->ops->enable_interrupt)
+ proc->ops->enable_interrupt(&proc->vdev.intr_info);
+ return 0;
+}
+
/**
* hil_enable_vring_notifications()
*
vring_hw->vq = vq;
if (proc_hw->ops->enable_interrupt) {
- proc_hw->ops->enable_interrupt(vring_hw);
+ proc_hw->ops->enable_interrupt(&vring_hw->intr_info);
}
return 0;
}
+/**
+ * hil_vdev_notify()
+ *
+ * This function generates IPI to let the other side know that there is
+ * update in the vritio dev configs
+ *
+ * @param vdev - pointer to the viritio device
+ *
+ */
+void hil_vdev_notify(struct virtio_device *vdev)
+{
+ struct hil_proc *proc = vdev->device;
+ struct proc_vdev *pvdev = &proc->vdev;
+
+ if (proc->ops->notify) {
+ proc->ops->notify(proc, &pvdev->intr_info);
+ }
+}
+
/**
* hil_vring_notify()
*
&proc_hw->vdev.vring_info[vq->vq_queue_index];
if (proc_hw->ops->notify) {
- proc_hw->ops->notify(proc_hw->cpu_id, &vring_hw->intr_info);
+ proc_hw->ops->notify(proc_hw, &vring_hw->intr_info);
}
}
{
if (proc->ops->boot_cpu) {
- proc->ops->boot_cpu(proc->cpu_id, start_addr);
+ proc->ops->boot_cpu(proc, start_addr);
}
#if defined (OPENAMP_BENCHMARK_ENABLE)
- boot_time_stamp = env_get_timestamp();
+ boot_time_stamp = metal_get_timestamp();
#endif
return 0;
void hil_shutdown_cpu(struct hil_proc *proc)
{
if (proc->ops->shutdown_cpu) {
- proc->ops->shutdown_cpu(proc->cpu_id);
+ proc->ops->shutdown_cpu(proc);
}
#if defined (OPENAMP_BENCHMARK_ENABLE)
- shutdown_time_stamp = env_get_timestamp();
+ shutdown_time_stamp = metal_get_timestamp();
#endif
}
* returns - status of function execution
*
*/
-int hil_get_firmware(char *fw_name, unsigned int *start_addr,
+int hil_get_firmware(char *fw_name, uintptr_t *start_addr,
unsigned int *size)
{
return (config_get_firmware(fw_name, start_addr, size));
}
+
+int hil_poll (struct hil_proc *proc, int nonblock)
+{
+ return proc->ops->poll(proc, nonblock);
+}
+
+int hil_set_shm (struct hil_proc *proc,
+ const char *bus_name, const char *name,
+ metal_phys_addr_t paddr, size_t size)
+{
+ struct metal_device *dev;
+ struct metal_io_region *io;
+ int ret;
+ if (!proc)
+ return -1;
+ if (name && bus_name) {
+ ret = metal_device_open(bus_name, name, &dev);
+ if (ret)
+ return ret;
+ io = metal_device_io_region(dev, 0);
+ if (!io)
+ return -1;
+ proc->sh_buff.io = io;
+ proc->sh_buff.dev = dev;
+ } else if (name) {
+ ret = metal_shmem_open(name, size, &io);
+ if (ret)
+ return ret;
+ proc->sh_buff.io = io;
+ }
+ if (!paddr && io) {
+ proc->sh_buff.start_paddr = io->physmap[0];
+ proc->sh_buff.start_addr = io->virt;
+ } else {
+ proc->sh_buff.start_paddr = paddr;
+ }
+ if (!size && io)
+ proc->sh_buff.size = io->size;
+ else
+ proc->sh_buff.size = size;
+
+ metal_io_mem_map(proc->sh_buff.start_paddr, proc->sh_buff.io,
+ proc->sh_buff.size);
+ return 0;
+}
+
+int hil_set_vring (struct hil_proc *proc, int index,
+ const char *bus_name, const char *name)
+{
+ struct metal_device *dev;
+ struct metal_io_region *io;
+ struct proc_vring *vring;
+ int ret;
+
+ if (!proc)
+ return -1;
+ if (index >= HIL_MAX_NUM_VRINGS)
+ return -1;
+ vring = &proc->vdev.vring_info[index];
+ if (name && bus_name) {
+ ret = metal_device_open(bus_name, name, &dev);
+ if (ret)
+ return ret;
+ io = metal_device_io_region(dev, 0);
+ if (!io)
+ return -1;
+ vring->io = io;
+ vring->dev = dev;
+ } else if (name) {
+ ret = metal_shmem_open(name, DEFAULT_VRING_MEM_SIZE, &io);
+ if (ret)
+ return ret;
+ vring->io = io;
+ }
+
+ return 0;
+}
+
+int hil_set_vdev_ipi (struct hil_proc *proc, int index,
+ unsigned int irq, void *data)
+{
+ struct proc_intr *vring_intr;
+
+ /* As we support only one vdev for now */
+ (void)index;
+
+ if (!proc)
+ return -1;
+ vring_intr = &proc->vdev.intr_info;
+ vring_intr->vect_id = irq;
+ vring_intr->data = data;
+ return 0;
+}
+
+int hil_set_vring_ipi (struct hil_proc *proc, int index,
+ unsigned int irq, void *data)
+{
+ struct proc_intr *vring_intr;
+
+ if (!proc)
+ return -1;
+ vring_intr = &proc->vdev.vring_info[index].intr_info;
+ vring_intr->vect_id = irq;
+ vring_intr->data = data;
+ return 0;
+}
+
+int hil_set_rpmsg_channel (struct hil_proc *proc, int index,
+ char *name)
+{
+ if (!proc)
+ return -1;
+ if (index >= HIL_MAX_NUM_CHANNELS)
+ return -1;
+ strcpy(proc->chnls[index].name, name);
+ return 0;
+}
+