diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index 96b9569cf0e..c3ce0a8f462 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -249,6 +249,10 @@ ifeq ($(CONFIG_SIM_LIBUSB),y) endif endif +ifeq ($(CONFIG_RPMSG_VIRTIO),y) + CSRCS += sim_rpmsg_virtio.c +endif + ifeq ($(CONFIG_RPTUN),y) CSRCS += sim_rptun.c endif diff --git a/arch/sim/src/sim/CMakeLists.txt b/arch/sim/src/sim/CMakeLists.txt index a02f3e5af1b..ccd91cfc9b1 100644 --- a/arch/sim/src/sim/CMakeLists.txt +++ b/arch/sim/src/sim/CMakeLists.txt @@ -117,6 +117,10 @@ if(CONFIG_LIBM_TOOLCHAIN) list(APPEND STDLIBS m) endif() +if(CONFIG_RPMSG_VIRTIO) + list(APPEND SRCS sim_rpmsg_vritio.c) +endif() + if(CONFIG_RPTUN) list(APPEND SRCS sim_rptun.c) endif() diff --git a/arch/sim/src/sim/sim_internal.h b/arch/sim/src/sim/sim_internal.h index 366d493157c..a78260eb085 100644 --- a/arch/sim/src/sim/sim_internal.h +++ b/arch/sim/src/sim/sim_internal.h @@ -409,6 +409,13 @@ void sim_netdriver_loop(void); int sim_rptun_init(const char *shmemname, const char *cpuname, int master); #endif +/* sim_rpmsg_virtio.c *******************************************************/ + +#ifdef CONFIG_RPMSG_VIRTIO +int sim_rpmsg_virtio_init(const char *shmemname, const char *cpuname, + bool master); +#endif + /* sim_hcisocket.c **********************************************************/ #ifdef CONFIG_SIM_HCISOCKET diff --git a/arch/sim/src/sim/sim_rpmsg_virtio.c b/arch/sim/src/sim/sim_rpmsg_virtio.c new file mode 100644 index 00000000000..a53d910dcf7 --- /dev/null +++ b/arch/sim/src/sim/sim_rpmsg_virtio.c @@ -0,0 +1,250 @@ +/**************************************************************************** + * arch/sim/src/sim/sim_rpmsg_virtio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "sim_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define SIM_RPMSG_VIRTIO_WORK_DELAY 1 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sim_rpmsg_virtio_shmem_s +{ + volatile uintptr_t base; + volatile unsigned int seqs; + volatile unsigned int seqm; + volatile unsigned int cmds; + volatile unsigned int cmdm; + volatile unsigned int boots; + volatile unsigned int bootm; + struct rpmsg_virtio_rsc_s rsc; + char buf[0x10000]; +}; + +struct sim_rpmsg_virtio_dev_s +{ + struct rpmsg_virtio_s dev; + rpmsg_virtio_callback_t callback; + void *arg; + int master; + uint32_t seq; + struct sim_rpmsg_virtio_shmem_s *shmem; + struct simple_addrenv_s addrenv; + char cpuname[RPMSG_NAME_SIZE + 1]; + char shmemname[RPMSG_NAME_SIZE + 1]; + + /* Work queue for transmit */ + + struct work_s worker; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static const char *sim_rpmsg_virtio_get_cpuname(struct rpmsg_virtio_s *dev) +{ + struct sim_rpmsg_virtio_dev_s *priv = + container_of(dev, struct sim_rpmsg_virtio_dev_s, dev); + + return priv->cpuname; +} + +static struct rpmsg_virtio_rsc_s * +sim_rpmsg_virtio_get_resource(struct rpmsg_virtio_s *dev) +{ + struct sim_rpmsg_virtio_dev_s *priv = + container_of(dev, struct sim_rpmsg_virtio_dev_s, dev); + struct rpmsg_virtio_rsc_s *rsc; + + priv->shmem = host_allocshmem(priv->shmemname, sizeof(*priv->shmem)); + if (!priv->shmem) + { + return NULL; + } + + rsc = &priv->shmem->rsc; + + if (priv->master) + { + memset(priv->shmem, 0, sizeof(*priv->shmem)); + rsc->rpmsg_vdev.id = VIRTIO_ID_RPMSG; + rsc->rpmsg_vdev.dfeatures = 1 << VIRTIO_RPMSG_F_NS | + 1 << VIRTIO_RPMSG_F_ACK; + rsc->rpmsg_vdev.config_len = sizeof(struct fw_rsc_config); + rsc->rpmsg_vdev.num_of_vrings = 2; + rsc->rpmsg_vring0.da = 0; + rsc->rpmsg_vring0.align = 8; + rsc->rpmsg_vring0.num = 8; + rsc->rpmsg_vring1.da = 0; + rsc->rpmsg_vring1.align = 8; + rsc->rpmsg_vring1.num = 8; + rsc->config.r2h_buf_size = 2048; + rsc->config.h2r_buf_size = 2048; + + priv->shmem->base = (uintptr_t)priv->shmem; + } + else + { + /* Wait untils master is ready */ + + while (priv->shmem->base == 0) + { + usleep(1000); + } + + priv->addrenv.va = (uintptr_t)priv->shmem; + priv->addrenv.pa = priv->shmem->base; + priv->addrenv.size = sizeof(*priv->shmem); + + simple_addrenv_initialize(&priv->addrenv); + } + + return rsc; +} + +static int sim_rpmsg_virtio_is_master(struct rpmsg_virtio_s *dev) +{ + struct sim_rpmsg_virtio_dev_s *priv = + container_of(dev, struct sim_rpmsg_virtio_dev_s, dev); + + return priv->master; +} + +static int +sim_rpmsg_virtio_register_callback(struct rpmsg_virtio_s *dev, + rpmsg_virtio_callback_t callback, + void *arg) +{ + struct sim_rpmsg_virtio_dev_s *priv = + container_of(dev, struct sim_rpmsg_virtio_dev_s, dev); + + priv->callback = callback; + priv->arg = arg; + + return 0; +} + +static void sim_rpmsg_virtio_work(void *arg) +{ + struct sim_rpmsg_virtio_dev_s *dev = arg; + + if (dev->shmem != NULL) + { + bool should_notify = false; + + if (dev->master && dev->seq != dev->shmem->seqs) + { + dev->seq = dev->shmem->seqs; + should_notify = true; + } + else if (!dev->master && dev->seq != dev->shmem->seqm) + { + dev->seq = dev->shmem->seqm; + should_notify = true; + } + + if (should_notify && dev->callback != NULL) + { + dev->callback(dev->arg, RPMSG_VIRTIO_NOTIFY_ALL); + } + } + + work_queue(HPWORK, &dev->worker, sim_rpmsg_virtio_work, + dev, SIM_RPMSG_VIRTIO_WORK_DELAY); +} + +static int sim_rpmsg_virtio_notify(struct rpmsg_virtio_s *dev, uint32_t vqid) +{ + struct sim_rpmsg_virtio_dev_s *priv = + container_of(dev, struct sim_rpmsg_virtio_dev_s, dev); + + if (priv->master) + { + priv->shmem->seqm++; + } + else + { + priv->shmem->seqs++; + } + + return 0; +} + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct rpmsg_virtio_ops_s g_sim_rpmsg_virtio_ops = +{ + .get_cpuname = sim_rpmsg_virtio_get_cpuname, + .get_resource = sim_rpmsg_virtio_get_resource, + .is_master = sim_rpmsg_virtio_is_master, + .notify = sim_rpmsg_virtio_notify, + .register_callback = sim_rpmsg_virtio_register_callback, +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int sim_rpmsg_virtio_init(const char *shmemname, const char *cpuname, + bool master) +{ + struct sim_rpmsg_virtio_dev_s *priv; + int ret; + + priv = kmm_zalloc(sizeof(*priv)); + if (priv == NULL) + { + return -ENOMEM; + } + + priv->master = master; + priv->dev.ops = &g_sim_rpmsg_virtio_ops; + strlcpy(priv->cpuname, cpuname, RPMSG_NAME_SIZE); + strlcpy(priv->shmemname, shmemname, RPMSG_NAME_SIZE); + + ret = rpmsg_virtio_initialize(&priv->dev); + if (ret < 0) + { + kmm_free(priv); + return ret; + } + + return work_queue(HPWORK, &priv->worker, sim_rpmsg_virtio_work, priv, 0); +}