index 746e681c2b2a29368cb92cb26e1611fac0c4ed81..ebb170f262190c80fc1e082eecfef24b450369c2 100644 (file)
#include <string.h>
#include "openamp/rpmsg.h"
+#include "openamp/remoteproc.h"
#include "metal/utilities.h"
#include "metal/alloc.h"
+#include "metal/atomic.h"
+#include "metal/cpu.h"
/* Macro to initialize vring HW info */
#define INIT_VRING_ALLOC_INFO(ring_info,vring_hw) \
* This function creates and initializes the remote device. The remote device
* encapsulates virtio device.
*
- * @param pdata - platform data for remote processor
+ * @param proc - pointer to hil_proc
* @param rdev - pointer to newly created remote device
- * @param dev-id - ID of device to create , remote cpu id
* @param role - role of the other device, Master or Remote
* @param channel_created - callback function for channel creation
* @param channel_destroyed - callback function for channel deletion
* @return - status of function execution
*
*/
-int rpmsg_rdev_init(void *pdata, struct remote_device **rdev, int dev_id, int role,
+int rpmsg_rdev_init(struct hil_proc *proc,
+ struct remote_device **rdev, int role,
rpmsg_chnl_cb_t channel_created,
rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb)
{
struct remote_device *rdev_loc;
struct virtio_device *virt_dev;
- struct hil_proc *proc;
struct proc_shm *shm;
int status;
+ if (!proc)
+ return RPMSG_ERR_PARAM;
/* Initialize HIL data structures for given device */
- proc = hil_create_proc(pdata, dev_id);
-
- if (!proc) {
- return RPMSG_ERR_DEV_ID;
- }
+ if (hil_init_proc(proc))
+ return RPMSG_ERR_DEV_INIT;
/* Create software representation of remote processor. */
rdev_loc = (struct remote_device *)metal_allocate_memory(sizeof(struct remote_device));
@@ -150,6 +151,9 @@ int rpmsg_rdev_init(void *pdata, struct remote_device **rdev, int dev_id, int ro
}
}
+ if (!rpmsg_rdev_remote_ready(rdev_loc))
+ return RPMSG_ERR_DEV_INIT;
+
/* Initialize endpoints list */
metal_list_init(&rdev_loc->rp_endpoints);
_destroy_endpoint(rdev, rp_ept);
}
- if (rdev->rvq) {
- virtqueue_free(rdev->rvq);
- }
- if (rdev->tvq) {
- virtqueue_free(rdev->tvq);
- }
+ metal_mutex_acquire(&rdev->lock);
+ rdev->rvq = 0;
+ rdev->tvq = 0;
if (rdev->mem_pool) {
sh_mem_delete_pool(rdev->mem_pool);
+ rdev->mem_pool = 0;
}
- metal_mutex_deinit(&rdev->lock);
+ metal_mutex_release(&rdev->lock);
+ hil_free_vqs(&rdev->virt_dev);
+
if (rdev->proc) {
hil_delete_proc(rdev->proc);
rdev->proc = 0;
}
+ metal_mutex_deinit(&rdev->lock);
metal_free_memory(rdev);
}
@@ -300,27 +305,11 @@ struct rpmsg_endpoint *rpmsg_rdev_get_endpoint_from_addr(struct remote_device *r
*/
int rpmsg_rdev_notify(struct remote_device *rdev)
{
- int status = RPMSG_SUCCESS;
+ struct virtio_device *vdev = &rdev->virt_dev;
- if (rdev->role == RPMSG_REMOTE) {
- status = hil_get_status(rdev->proc);
-
- /*
- * Let the remote device know that Master is ready for
- * communication.
- */
- if (!status)
- virtqueue_kick(rdev->rvq);
-
- } else {
- status = hil_set_status(rdev->proc);
- }
-
- if (status == RPMSG_SUCCESS) {
- rdev->state = RPMSG_DEV_STATE_ACTIVE;
- }
+ hil_vdev_notify(vdev);
- return status;
+ return RPMSG_SUCCESS;
}
/**
return RPMSG_SUCCESS;
}
+/**
+ * check if the remote is ready to start RPMsg communication
+ */
+int rpmsg_rdev_remote_ready(struct remote_device *rdev)
+{
+ struct virtio_device *vdev = &rdev->virt_dev;
+ uint8_t status;
+ if (rdev->role == RPMSG_MASTER) {
+ while (1) {
+ /* Busy wait until the remote is ready */
+ status = vdev->func->get_status(vdev);
+ if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK)
+ return true;
+ metal_cpu_yield();
+ }
+ } else {
+ return true;
+ }
+ /* Never come here */
+ return false;
+}
+
static void rpmsg_memset_io(struct metal_io_region *io, void *dst, int c, size_t count)
{
if ((io->mem_flags & METAL_IO_MAPPED)) {
@@ -469,14 +480,28 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
unsigned char rpmsg_rdev_get_status(struct virtio_device *dev)
{
- (void)dev;
- return 0;
+ struct hil_proc *proc = dev->device;
+ struct proc_vdev *pvdev = &proc->vdev;
+ struct fw_rsc_vdev *vdev_rsc = pvdev->vdev_info;
+
+ if (!vdev_rsc)
+ return -1;
+
+ return vdev_rsc->status;
}
void rpmsg_rdev_set_status(struct virtio_device *dev, unsigned char status)
{
- (void)dev;
- (void)status;
+ struct hil_proc *proc = dev->device;
+ struct proc_vdev *pvdev = &proc->vdev;
+ struct fw_rsc_vdev *vdev_rsc = pvdev->vdev_info;
+
+ if (!vdev_rsc)
+ return;
+
+ vdev_rsc->status = status;
+
+ atomic_thread_fence(memory_order_seq_cst);
}
uint32_t rpmsg_rdev_get_feature(struct virtio_device *dev)