2019-11-02 18:30:33 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* drivers/rptun/rptun.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2017 Pinecone Inc. All rights reserved.
|
|
|
|
* Author: Guiding Li<liguiding@pinecone.net>
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
|
|
* used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Included Files
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
|
2019-11-03 14:28:17 +01:00
|
|
|
#include <inttypes.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
2019-11-02 18:30:33 +01:00
|
|
|
#include <nuttx/arch.h>
|
|
|
|
#include <nuttx/kmalloc.h>
|
|
|
|
#include <nuttx/kthread.h>
|
|
|
|
#include <nuttx/rptun/openamp.h>
|
|
|
|
#include <nuttx/rptun/rptun.h>
|
|
|
|
#include <nuttx/signal.h>
|
|
|
|
#include <metal/utilities.h>
|
|
|
|
|
2019-11-03 14:28:17 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Pre-processor Definitions
|
|
|
|
****************************************************************************/
|
2019-11-02 18:30:33 +01:00
|
|
|
|
|
|
|
#ifndef MAX
|
|
|
|
# define MAX(a,b) ((a) > (b) ? (a) : (b))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef ALIGN_UP
|
|
|
|
# define ALIGN_UP(s, a) (((s) + (a) - 1) & ~((a) - 1))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Types
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
struct rptun_priv_s
|
|
|
|
{
|
|
|
|
FAR struct rptun_dev_s *dev;
|
|
|
|
struct remoteproc rproc;
|
|
|
|
struct rpmsg_virtio_device vdev;
|
|
|
|
struct rpmsg_virtio_shm_pool shm_pool;
|
|
|
|
struct metal_list bind;
|
|
|
|
struct metal_list node;
|
|
|
|
int pid;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rptun_bind_s
|
|
|
|
{
|
|
|
|
char name[RPMSG_NAME_SIZE];
|
|
|
|
uint32_t dest;
|
|
|
|
struct metal_list node;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rptun_cb_s
|
|
|
|
{
|
|
|
|
FAR void *priv;
|
|
|
|
rpmsg_dev_cb_t device_created;
|
|
|
|
rpmsg_dev_cb_t device_destroy;
|
|
|
|
rpmsg_bind_cb_t ns_bind;
|
|
|
|
struct metal_list node;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rptun_store_s
|
|
|
|
{
|
2019-11-03 14:33:04 +01:00
|
|
|
struct file file;
|
|
|
|
FAR char *buf;
|
2019-11-02 18:30:33 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Function Prototypes
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static FAR struct remoteproc *rptun_init(FAR struct remoteproc *rproc,
|
|
|
|
FAR struct remoteproc_ops *ops,
|
|
|
|
FAR void *arg);
|
|
|
|
static void rptun_remove(FAR struct remoteproc *rproc);
|
|
|
|
static int rptun_mmap(FAR struct remoteproc *rproc,
|
|
|
|
FAR metal_phys_addr_t *pa, FAR metal_phys_addr_t *da,
|
|
|
|
FAR void **va, size_t size, unsigned int attribute,
|
|
|
|
FAR struct metal_io_region **io_);
|
|
|
|
static int rptun_start(FAR struct remoteproc *rproc);
|
|
|
|
static int rptun_stop(FAR struct remoteproc *rproc);
|
|
|
|
static int rptun_notify(FAR struct remoteproc *rproc, uint32_t id);
|
|
|
|
|
|
|
|
static void rptun_ns_bind(FAR struct rpmsg_device *rdev,
|
|
|
|
FAR const char *name, uint32_t dest);
|
|
|
|
|
|
|
|
static int rptun_dev_start(FAR struct remoteproc *rproc);
|
|
|
|
static int rptun_dev_stop(FAR struct remoteproc *rproc);
|
|
|
|
static int rptun_dev_ioctl(FAR struct file *filep, int cmd,
|
|
|
|
unsigned long arg);
|
|
|
|
|
|
|
|
static int rptun_store_open(FAR void *store_, FAR const char *path,
|
|
|
|
FAR const void **img_data);
|
|
|
|
static void rptun_store_close(FAR void *store_);
|
|
|
|
static int rptun_store_load(FAR void *store_, size_t offset,
|
|
|
|
size_t size, FAR const void **data,
|
|
|
|
metal_phys_addr_t pa,
|
|
|
|
FAR struct metal_io_region *io,
|
|
|
|
char is_blocking);
|
|
|
|
|
|
|
|
static metal_phys_addr_t rptun_pa_to_da(FAR struct rptun_dev_s *dev,
|
|
|
|
metal_phys_addr_t pa);
|
|
|
|
static metal_phys_addr_t rptun_da_to_pa(FAR struct rptun_dev_s *dev,
|
|
|
|
metal_phys_addr_t da);
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Data
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static struct remoteproc_ops g_rptun_ops =
|
|
|
|
{
|
|
|
|
.init = rptun_init,
|
|
|
|
.remove = rptun_remove,
|
|
|
|
.mmap = rptun_mmap,
|
|
|
|
.start = rptun_start,
|
|
|
|
.stop = rptun_stop,
|
|
|
|
.notify = rptun_notify,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct file_operations g_rptun_devops =
|
|
|
|
{
|
|
|
|
.ioctl = rptun_dev_ioctl,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct image_store_ops g_rptun_storeops =
|
|
|
|
{
|
|
|
|
.open = rptun_store_open,
|
|
|
|
.close = rptun_store_close,
|
|
|
|
.load = rptun_store_load,
|
|
|
|
.features = SUPPORT_SEEK,
|
|
|
|
};
|
|
|
|
|
|
|
|
static sem_t g_rptun_sem = SEM_INITIALIZER(1);
|
|
|
|
|
|
|
|
static METAL_DECLARE_LIST(g_rptun_cb);
|
|
|
|
static METAL_DECLARE_LIST(g_rptun_priv);
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int rptun_thread(int argc, FAR char *argv[])
|
|
|
|
{
|
|
|
|
FAR struct rptun_priv_s *priv;
|
|
|
|
sigset_t set;
|
|
|
|
int ret;
|
|
|
|
|
2019-11-10 15:45:14 +01:00
|
|
|
priv = (FAR struct rptun_priv_s *)((uintptr_t)strtoul(argv[2], NULL, 0));
|
2019-11-02 18:30:33 +01:00
|
|
|
|
|
|
|
sigemptyset(&set);
|
|
|
|
sigaddset(&set, SIGUSR1);
|
|
|
|
nxsig_procmask(SIG_BLOCK, &set, NULL);
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
ret = nxsig_timedwait(&set, NULL, NULL);
|
|
|
|
if (ret == SIGUSR1)
|
|
|
|
{
|
|
|
|
remoteproc_get_notification(&priv->rproc, RPTUN_NOTIFY_ALL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rptun_callback(FAR void *arg, uint32_t vqid)
|
|
|
|
{
|
|
|
|
FAR struct rptun_priv_s *priv = arg;
|
|
|
|
|
|
|
|
return nxsig_kill(priv->pid, SIGUSR1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static FAR struct remoteproc *rptun_init(FAR struct remoteproc *rproc,
|
|
|
|
FAR struct remoteproc_ops *ops,
|
|
|
|
FAR void *arg)
|
|
|
|
{
|
|
|
|
rproc->ops = ops;
|
|
|
|
rproc->priv = arg;
|
|
|
|
|
|
|
|
return rproc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rptun_remove(FAR struct remoteproc *rproc)
|
|
|
|
{
|
|
|
|
rproc->priv = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rptun_mmap(FAR struct remoteproc *rproc,
|
|
|
|
FAR metal_phys_addr_t *pa, FAR metal_phys_addr_t *da,
|
|
|
|
FAR void **va, size_t size, unsigned int attribute,
|
|
|
|
FAR struct metal_io_region **io_)
|
|
|
|
{
|
|
|
|
FAR struct rptun_priv_s *priv = rproc->priv;
|
|
|
|
FAR struct metal_io_region *io = metal_io_get_region();
|
|
|
|
|
|
|
|
if (*pa != METAL_BAD_PHYS)
|
|
|
|
{
|
|
|
|
*da = rptun_pa_to_da(priv->dev, *pa);
|
|
|
|
*va = metal_io_phys_to_virt(io, *pa);
|
|
|
|
if (!*va)
|
|
|
|
{
|
|
|
|
return -RPROC_EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (*da != METAL_BAD_PHYS)
|
|
|
|
{
|
|
|
|
*pa = rptun_da_to_pa(priv->dev, *da);
|
|
|
|
*va = metal_io_phys_to_virt(io, *pa);
|
|
|
|
if (!*va)
|
|
|
|
{
|
|
|
|
return -RPROC_EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (*va)
|
|
|
|
{
|
|
|
|
*pa = metal_io_virt_to_phys(io, *va);
|
|
|
|
if (*pa == METAL_BAD_PHYS)
|
|
|
|
{
|
|
|
|
return -RPROC_EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*da = rptun_pa_to_da(priv->dev, *pa);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return -RPROC_EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (io_)
|
|
|
|
{
|
|
|
|
*io_ = io;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rptun_start(FAR struct remoteproc *rproc)
|
|
|
|
{
|
|
|
|
FAR struct rptun_priv_s *priv = rproc->priv;
|
|
|
|
|
|
|
|
if (RPTUN_IS_MASTER(priv->dev))
|
|
|
|
{
|
|
|
|
return RPTUN_START(priv->dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rptun_stop(FAR struct remoteproc *rproc)
|
|
|
|
{
|
|
|
|
FAR struct rptun_priv_s *priv = rproc->priv;
|
|
|
|
|
|
|
|
if (RPTUN_IS_MASTER(priv->dev))
|
|
|
|
{
|
|
|
|
return RPTUN_STOP(priv->dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rptun_notify(FAR struct remoteproc *rproc, uint32_t id)
|
|
|
|
{
|
|
|
|
FAR struct rptun_priv_s *priv = rproc->priv;
|
|
|
|
|
|
|
|
RPTUN_NOTIFY(priv->dev, RPTUN_NOTIFY_ALL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *rptun_get_priv_by_rdev(FAR struct rpmsg_device *rdev)
|
|
|
|
{
|
|
|
|
struct rpmsg_virtio_device *rvdev;
|
|
|
|
struct virtio_device *vdev;
|
|
|
|
struct remoteproc_virtio *rpvdev;
|
|
|
|
struct remoteproc *rproc;
|
|
|
|
|
|
|
|
rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev);
|
|
|
|
vdev = rvdev->vdev;
|
|
|
|
if (!vdev)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
|
|
|
|
rproc = rpvdev->priv;
|
|
|
|
if (!rproc)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rproc->priv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rptun_ns_bind(FAR struct rpmsg_device *rdev,
|
|
|
|
FAR const char *name, uint32_t dest)
|
|
|
|
{
|
|
|
|
FAR struct rptun_priv_s *priv = rptun_get_priv_by_rdev(rdev);
|
|
|
|
FAR struct rptun_bind_s *bind;
|
|
|
|
|
|
|
|
bind = kmm_malloc(sizeof(struct rptun_bind_s));
|
|
|
|
if (bind)
|
|
|
|
{
|
|
|
|
FAR struct metal_list *node;
|
|
|
|
FAR struct rptun_cb_s *cb;
|
|
|
|
|
|
|
|
bind->dest = dest;
|
|
|
|
strncpy(bind->name, name, RPMSG_NAME_SIZE);
|
|
|
|
|
|
|
|
nxsem_wait(&g_rptun_sem);
|
|
|
|
|
|
|
|
metal_list_add_tail(&priv->bind, &bind->node);
|
|
|
|
|
|
|
|
metal_list_for_each(&g_rptun_cb, node)
|
|
|
|
{
|
|
|
|
cb = metal_container_of(node, struct rptun_cb_s, node);
|
|
|
|
if (cb->ns_bind)
|
|
|
|
{
|
|
|
|
cb->ns_bind(rdev, cb->priv, name, dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nxsem_post(&g_rptun_sem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rptun_dev_start(FAR struct remoteproc *rproc)
|
|
|
|
{
|
|
|
|
FAR struct rptun_priv_s *priv = rproc->priv;
|
|
|
|
FAR struct virtio_device *vdev;
|
|
|
|
FAR struct rptun_rsc_s *rsc;
|
|
|
|
FAR struct metal_list *node;
|
|
|
|
FAR struct rptun_cb_s *cb;
|
|
|
|
unsigned int role = RPMSG_REMOTE;
|
|
|
|
int ret;
|
|
|
|
|
2019-11-11 16:09:40 +01:00
|
|
|
ret = remoteproc_config(&priv->rproc, NULL);
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-11-02 18:30:33 +01:00
|
|
|
if (RPTUN_GET_FIRMWARE(priv->dev))
|
|
|
|
{
|
|
|
|
struct rptun_store_s store =
|
|
|
|
{
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
ret = remoteproc_load(rproc, RPTUN_GET_FIRMWARE(priv->dev),
|
|
|
|
&store, &g_rptun_storeops, NULL);
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
rsc = rproc->rsc_table;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rsc = RPTUN_GET_RESOURCE(priv->dev);
|
|
|
|
if (!rsc)
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = remoteproc_set_rsc_table(rproc, (struct resource_table *)rsc,
|
|
|
|
sizeof(struct rptun_rsc_s));
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update resource table on MASTER side */
|
|
|
|
|
|
|
|
if (RPTUN_IS_MASTER(priv->dev))
|
|
|
|
{
|
|
|
|
uint32_t tbsz;
|
|
|
|
uint32_t v0sz;
|
|
|
|
uint32_t v1sz;
|
|
|
|
uint32_t shbufsz;
|
|
|
|
metal_phys_addr_t da0;
|
|
|
|
metal_phys_addr_t da1;
|
|
|
|
uint32_t align0;
|
|
|
|
uint32_t align1;
|
|
|
|
FAR void *va0;
|
|
|
|
FAR void *va1;
|
|
|
|
FAR void *shbuf;
|
|
|
|
|
|
|
|
align0 = B2C(rsc->rpmsg_vring0.align);
|
|
|
|
align1 = B2C(rsc->rpmsg_vring1.align);
|
|
|
|
|
|
|
|
tbsz = ALIGN_UP(sizeof(struct rptun_rsc_s), MAX(align0, align1));
|
2019-11-11 16:11:17 +01:00
|
|
|
v0sz = ALIGN_UP(vring_size(rsc->rpmsg_vring0.num, align0), align0);
|
|
|
|
v1sz = ALIGN_UP(vring_size(rsc->rpmsg_vring1.num, align1), align1);
|
2019-11-02 18:30:33 +01:00
|
|
|
|
|
|
|
va0 = (char *)rsc + tbsz;
|
|
|
|
va1 = (char *)rsc + tbsz + v0sz;
|
|
|
|
|
|
|
|
da0 = da1 = METAL_BAD_PHYS;
|
|
|
|
|
|
|
|
remoteproc_mmap(rproc, NULL, &da0, &va0, v0sz, 0, NULL);
|
|
|
|
remoteproc_mmap(rproc, NULL, &da1, &va1, v1sz, 0, NULL);
|
|
|
|
|
|
|
|
rsc->rpmsg_vring0.da = da0;
|
|
|
|
rsc->rpmsg_vring1.da = da1;
|
|
|
|
|
|
|
|
shbuf = (FAR char *)rsc + tbsz + v0sz + v1sz;
|
|
|
|
shbufsz = rsc->buf_size *
|
|
|
|
(rsc->rpmsg_vring0.num + rsc->rpmsg_vring1.num);
|
|
|
|
|
|
|
|
rpmsg_virtio_init_shm_pool(&priv->shm_pool, shbuf, shbufsz);
|
|
|
|
|
|
|
|
role = RPMSG_MASTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remote proc create */
|
|
|
|
|
|
|
|
vdev = remoteproc_create_virtio(rproc, 0, role, NULL);
|
|
|
|
if (!vdev)
|
|
|
|
{
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = rpmsg_init_vdev(&priv->vdev, vdev, rptun_ns_bind,
|
|
|
|
metal_io_get_region(), &priv->shm_pool);
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
remoteproc_remove_virtio(rproc, vdev);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remote proc start */
|
|
|
|
|
|
|
|
ret = remoteproc_start(rproc);
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
remoteproc_remove_virtio(rproc, vdev);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
nxsem_wait(&g_rptun_sem);
|
|
|
|
|
|
|
|
/* Add priv to list */
|
|
|
|
|
|
|
|
metal_list_add_tail(&g_rptun_priv, &priv->node);
|
|
|
|
|
|
|
|
/* Broadcast device_created to all registers */
|
|
|
|
|
|
|
|
metal_list_for_each(&g_rptun_cb, node)
|
|
|
|
{
|
|
|
|
cb = metal_container_of(node, struct rptun_cb_s, node);
|
|
|
|
if (cb->device_created)
|
|
|
|
{
|
|
|
|
cb->device_created(&priv->vdev.rdev, cb->priv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nxsem_post(&g_rptun_sem);
|
|
|
|
|
|
|
|
/* Register callback to mbox for receving remote message */
|
|
|
|
|
|
|
|
RPTUN_REGISTER_CALLBACK(priv->dev, rptun_callback, priv);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rptun_dev_stop(FAR struct remoteproc *rproc)
|
|
|
|
{
|
|
|
|
FAR struct rptun_priv_s *priv = rproc->priv;
|
|
|
|
FAR struct metal_list *node;
|
|
|
|
FAR struct rptun_cb_s *cb;
|
|
|
|
|
|
|
|
/* Unregister callback from mbox */
|
|
|
|
|
|
|
|
RPTUN_UNREGISTER_CALLBACK(priv->dev);
|
|
|
|
|
|
|
|
nxsem_wait(&g_rptun_sem);
|
|
|
|
|
|
|
|
/* Remove priv from list */
|
|
|
|
|
|
|
|
metal_list_del(&priv->node);
|
|
|
|
|
|
|
|
/* Broadcast device_destroy to all registers */
|
|
|
|
|
|
|
|
metal_list_for_each(&g_rptun_cb, node)
|
|
|
|
{
|
|
|
|
cb = metal_container_of(node, struct rptun_cb_s, node);
|
|
|
|
if (cb->device_destroy)
|
|
|
|
{
|
|
|
|
cb->device_destroy(&priv->vdev.rdev, cb->priv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nxsem_post(&g_rptun_sem);
|
|
|
|
|
2019-11-11 16:09:40 +01:00
|
|
|
/* Remote proc stop and shutdown */
|
2019-11-02 18:30:33 +01:00
|
|
|
|
2019-11-11 16:09:40 +01:00
|
|
|
remoteproc_shutdown(rproc);
|
2019-11-02 18:30:33 +01:00
|
|
|
|
|
|
|
/* Remote proc remove */
|
|
|
|
|
|
|
|
remoteproc_remove_virtio(rproc, priv->vdev.vdev);
|
|
|
|
rpmsg_deinit_vdev(&priv->vdev);
|
|
|
|
|
|
|
|
/* Free bind list */
|
|
|
|
|
|
|
|
metal_list_for_each(&priv->bind, node)
|
|
|
|
{
|
|
|
|
struct rptun_bind_s *bind;
|
|
|
|
|
|
|
|
bind = metal_container_of(node, struct rptun_bind_s, node);
|
|
|
|
kmm_free(bind);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rptun_dev_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
FAR struct inode *inode = filep->f_inode;
|
|
|
|
FAR struct rptun_priv_s *priv = inode->i_private;
|
|
|
|
int ret = -ENOTTY;
|
|
|
|
|
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case RPTUNIOC_START:
|
2019-11-11 16:09:40 +01:00
|
|
|
if (priv->rproc.state == RPROC_OFFLINE)
|
2019-11-02 18:30:33 +01:00
|
|
|
{
|
|
|
|
ret = rptun_dev_start(&priv->rproc);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RPTUNIOC_STOP:
|
2019-11-11 16:09:40 +01:00
|
|
|
if (priv->rproc.state != RPROC_OFFLINE)
|
2019-11-02 18:30:33 +01:00
|
|
|
{
|
|
|
|
ret = rptun_dev_stop(&priv->rproc);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rptun_store_open(FAR void *store_, FAR const char *path,
|
|
|
|
FAR const void **img_data)
|
|
|
|
{
|
|
|
|
FAR struct rptun_store_s *store = store_;
|
|
|
|
int len = 0x100;
|
2019-11-03 14:33:04 +01:00
|
|
|
int ret;
|
2019-11-02 18:30:33 +01:00
|
|
|
|
2019-11-03 14:33:04 +01:00
|
|
|
ret = file_open(&store->file, path, O_RDONLY);
|
|
|
|
if (ret < 0)
|
2019-11-02 18:30:33 +01:00
|
|
|
{
|
2019-11-03 14:33:04 +01:00
|
|
|
return ret;
|
2019-11-02 18:30:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
store->buf = kmm_malloc(len);
|
|
|
|
if (!store->buf)
|
|
|
|
{
|
2019-11-03 14:33:04 +01:00
|
|
|
file_close(&store->file);
|
2019-11-02 18:30:33 +01:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
*img_data = store->buf;
|
|
|
|
|
2019-11-03 14:33:04 +01:00
|
|
|
return file_read(&store->file, store->buf, len);
|
2019-11-02 18:30:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void rptun_store_close(FAR void *store_)
|
|
|
|
{
|
|
|
|
FAR struct rptun_store_s *store = store_;
|
|
|
|
|
|
|
|
kmm_free(store->buf);
|
2019-11-03 14:33:04 +01:00
|
|
|
file_close(&store->file);
|
2019-11-02 18:30:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rptun_store_load(FAR void *store_, size_t offset,
|
|
|
|
size_t size, FAR const void **data,
|
|
|
|
metal_phys_addr_t pa,
|
|
|
|
FAR struct metal_io_region *io,
|
|
|
|
char is_blocking)
|
|
|
|
{
|
|
|
|
FAR struct rptun_store_s *store = store_;
|
|
|
|
FAR char *tmp;
|
|
|
|
|
|
|
|
if (pa == METAL_BAD_PHYS)
|
|
|
|
{
|
|
|
|
tmp = kmm_realloc(store->buf, size);
|
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
store->buf = tmp;
|
|
|
|
*data = tmp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tmp = metal_io_phys_to_virt(io, pa);
|
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-03 14:33:04 +01:00
|
|
|
file_seek(&store->file, offset, SEEK_SET);
|
|
|
|
return file_read(&store->file, tmp, size);
|
2019-11-02 18:30:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static metal_phys_addr_t rptun_pa_to_da(FAR struct rptun_dev_s *dev,
|
|
|
|
metal_phys_addr_t pa)
|
|
|
|
{
|
|
|
|
FAR const struct rptun_addrenv_s *addrenv;
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
addrenv = RPTUN_GET_ADDRENV(dev);
|
|
|
|
if (!addrenv)
|
|
|
|
{
|
|
|
|
return pa;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; addrenv[i].size; i++)
|
|
|
|
{
|
|
|
|
if (pa - addrenv[i].pa < addrenv[i].size)
|
|
|
|
{
|
|
|
|
return addrenv[i].da + (pa - addrenv[i].pa);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pa;
|
|
|
|
}
|
|
|
|
|
|
|
|
static metal_phys_addr_t rptun_da_to_pa(FAR struct rptun_dev_s *dev,
|
|
|
|
metal_phys_addr_t da)
|
|
|
|
{
|
|
|
|
FAR const struct rptun_addrenv_s *addrenv;
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
addrenv = RPTUN_GET_ADDRENV(dev);
|
|
|
|
if (!addrenv)
|
|
|
|
{
|
|
|
|
return da;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; addrenv[i].size; i++)
|
|
|
|
{
|
|
|
|
if (da - addrenv[i].da < addrenv[i].size)
|
|
|
|
{
|
|
|
|
return addrenv[i].pa + (da - addrenv[i].da);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return da;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
FAR const char *rpmsg_get_cpuname(FAR struct rpmsg_device *rdev)
|
|
|
|
{
|
|
|
|
FAR struct rptun_priv_s *priv = rptun_get_priv_by_rdev(rdev);
|
|
|
|
|
|
|
|
return RPTUN_GET_CPUNAME(priv->dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
int rpmsg_register_callback(FAR void *priv_,
|
|
|
|
rpmsg_dev_cb_t device_created,
|
|
|
|
rpmsg_dev_cb_t device_destroy,
|
|
|
|
rpmsg_bind_cb_t ns_bind)
|
|
|
|
{
|
|
|
|
FAR struct metal_list *node;
|
|
|
|
FAR struct metal_list *bnode;
|
|
|
|
FAR struct rptun_cb_s *cb;
|
|
|
|
|
|
|
|
cb = kmm_zalloc(sizeof(struct rptun_cb_s));
|
|
|
|
if (!cb)
|
|
|
|
{
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
cb->priv = priv_;
|
|
|
|
cb->device_created = device_created;
|
|
|
|
cb->device_destroy = device_destroy;
|
|
|
|
cb->ns_bind = ns_bind;
|
|
|
|
|
|
|
|
nxsem_wait(&g_rptun_sem);
|
|
|
|
|
|
|
|
metal_list_add_tail(&g_rptun_cb, &cb->node);
|
|
|
|
|
|
|
|
metal_list_for_each(&g_rptun_priv, node)
|
|
|
|
{
|
|
|
|
struct rptun_priv_s *priv;
|
|
|
|
|
|
|
|
priv = metal_container_of(node, struct rptun_priv_s, node);
|
|
|
|
if (device_created)
|
|
|
|
{
|
|
|
|
device_created(&priv->vdev.rdev, priv_);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ns_bind)
|
|
|
|
{
|
|
|
|
metal_list_for_each(&priv->bind, bnode)
|
|
|
|
{
|
|
|
|
struct rptun_bind_s *bind;
|
|
|
|
|
|
|
|
bind = metal_container_of(bnode, struct rptun_bind_s, node);
|
|
|
|
ns_bind(&priv->vdev.rdev, priv_, bind->name, bind->dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nxsem_post(&g_rptun_sem);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rpmsg_unregister_callback(FAR void *priv_,
|
|
|
|
rpmsg_dev_cb_t device_created,
|
|
|
|
rpmsg_dev_cb_t device_destroy,
|
|
|
|
rpmsg_bind_cb_t ns_bind)
|
|
|
|
{
|
|
|
|
FAR struct metal_list *node;
|
|
|
|
FAR struct metal_list *pnode;
|
|
|
|
|
|
|
|
nxsem_wait(&g_rptun_sem);
|
|
|
|
|
|
|
|
metal_list_for_each(&g_rptun_cb, node)
|
|
|
|
{
|
|
|
|
struct rptun_cb_s *cb = NULL;
|
|
|
|
|
|
|
|
cb = metal_container_of(node, struct rptun_cb_s, node);
|
|
|
|
if (cb->priv == priv_ &&
|
|
|
|
cb->device_created == device_created &&
|
|
|
|
cb->device_destroy == device_destroy &&
|
|
|
|
cb->ns_bind == ns_bind)
|
|
|
|
{
|
|
|
|
if (device_destroy)
|
|
|
|
{
|
|
|
|
metal_list_for_each(&g_rptun_priv, pnode)
|
|
|
|
{
|
|
|
|
struct rptun_priv_s *priv;
|
|
|
|
|
|
|
|
priv = metal_container_of(pnode, struct rptun_priv_s, node);
|
|
|
|
device_destroy(&priv->vdev.rdev, priv_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
metal_list_del(&cb->node);
|
|
|
|
kmm_free(cb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nxsem_post(&g_rptun_sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
int rptun_initialize(FAR struct rptun_dev_s *dev)
|
|
|
|
{
|
|
|
|
struct metal_init_params params = METAL_INIT_DEFAULTS;
|
|
|
|
FAR struct rptun_priv_s *priv;
|
2019-11-10 15:45:14 +01:00
|
|
|
FAR char *argv[3];
|
2019-11-03 14:28:17 +01:00
|
|
|
char arg1[16];
|
2019-11-10 15:45:14 +01:00
|
|
|
char name[32];
|
2019-11-02 18:30:33 +01:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = metal_init(¶ms);
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
priv = kmm_zalloc(sizeof(struct rptun_priv_s));
|
|
|
|
if (priv == NULL)
|
|
|
|
{
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2019-11-03 14:28:17 +01:00
|
|
|
snprintf(arg1, 16, "0x%" PRIxPTR, (uintptr_t)priv);
|
2019-11-02 18:30:33 +01:00
|
|
|
|
2019-11-10 15:45:14 +01:00
|
|
|
argv[0] = (void *)RPTUN_GET_CPUNAME(dev);
|
|
|
|
argv[1] = arg1;
|
|
|
|
argv[2] = NULL;
|
|
|
|
|
|
|
|
ret = kthread_create("rptun",
|
2019-11-02 18:30:33 +01:00
|
|
|
CONFIG_RPTUN_PRIORITY,
|
|
|
|
CONFIG_RPTUN_STACKSIZE,
|
|
|
|
rptun_thread,
|
|
|
|
argv);
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
kmm_free(priv);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
priv->pid = ret;
|
|
|
|
priv->dev = dev;
|
|
|
|
|
|
|
|
metal_list_init(&priv->bind);
|
|
|
|
remoteproc_init(&priv->rproc, &g_rptun_ops, priv);
|
|
|
|
|
|
|
|
if (RPTUN_IS_AUTOSTART(dev))
|
|
|
|
{
|
|
|
|
rptun_dev_start(&priv->rproc);
|
|
|
|
}
|
|
|
|
|
2019-11-10 15:45:14 +01:00
|
|
|
snprintf(name, 32, "/dev/rptun/%s", RPTUN_GET_CPUNAME(dev));
|
2019-11-02 18:30:33 +01:00
|
|
|
return register_driver(name, &g_rptun_devops, 0666, priv);
|
|
|
|
}
|
|
|
|
|
|
|
|
int rptun_boot(FAR const char *cpuname)
|
|
|
|
{
|
2019-11-03 14:33:04 +01:00
|
|
|
struct file file;
|
2019-11-10 15:45:14 +01:00
|
|
|
char name[32];
|
2019-11-02 18:30:33 +01:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!cpuname)
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-11-10 15:45:14 +01:00
|
|
|
snprintf(name, 32, "/dev/rptun/%s", cpuname);
|
2019-11-03 14:33:04 +01:00
|
|
|
ret = file_open(&file, name, 0, 0);
|
2019-11-02 18:30:33 +01:00
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-11-03 14:33:04 +01:00
|
|
|
ret = file_ioctl(&file, RPTUNIOC_START, 0);
|
|
|
|
file_close(&file);
|
2019-11-02 18:30:33 +01:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|