/* * SPDX-FileCopyrightText: Copyright 2022-2024 Arm Limited and/or its affiliates * SPDX-License-Identifier: Apache-2.0 * * Licensed 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 * * 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. */ /***************************************************************************** * Includes *****************************************************************************/ #include "remoteproc.hpp" #include #include namespace { void setupRProcMem(remoteproc &rproc, metal_phys_addr_t pa, metal_phys_addr_t da, size_t size, remoteproc_mem &mem, metal_io_region ®ion) { remoteproc_init_mem(&mem, nullptr, pa, da, size, ®ion); metal_io_init(®ion, (void *)da, &mem.pa, size, -1, 0, nullptr); remoteproc_add_mem(&rproc, &mem); } }; // namespace /***************************************************************************** * RProc *****************************************************************************/ RProc::RProc(Mailbox::Mailbox &_mailbox, resource_table &table, size_t tableSize) : mailbox(_mailbox), ops({}), vdev(nullptr), rsc_mem(), rsc_region(), mems(), regions(), notifySemaphore(xSemaphoreCreateBinary()), notifyHandle() { ops.init = init; // initialize the remoteproc instance ops.remove = remove; // remove the remoteproc instance ops.handle_rsc = handle_rsc; // handle the vendor specific resource ops.notify = notify; // notify the remote mailbox.registerCallback(mailboxCallback, static_cast(this)); if (!remoteproc_init(&rproc, &ops, this)) { LOG_ERR("Failed to intialize remoteproc"); abort(); } // Setup memory region for resource table const metal_phys_addr_t rsc_addr = reinterpret_cast(&table); // No translation is needed for rsc_addr because it already contains the DA // so PA is set to DA setupRProcMem(rproc, rsc_addr, rsc_addr, tableSize, rsc_mem, rsc_region); int ret = remoteproc_set_rsc_table(&rproc, &table, tableSize); if (ret) { LOG_ERR("Failed to set resource table. ret=%d", ret); abort(); } vdev = remoteproc_create_virtio(&rproc, 0, VIRTIO_DEV_DEVICE, nullptr); if (!vdev) { LOG_ERR("Failed to create vdev"); abort(); } BaseType_t taskret = xTaskCreate(notifyTask, "notifyTask", 1024, this, 2, ¬ifyHandle); if (taskret != pdPASS) { LOG_ERR("Failed to create remoteproc notify task"); abort(); } } RProc::~RProc() { mailbox.deregisterCallback(mailboxCallback, static_cast(this)); vTaskDelete(notifyHandle); vSemaphoreDelete(notifySemaphore); } remoteproc *RProc::getRProc() { return &rproc; } virtio_device *RProc::getVDev() { return vdev; } void RProc::mailboxCallback(void *userArg) { auto _this = static_cast(userArg); xSemaphoreGiveFromISR(_this->notifySemaphore, nullptr); } void RProc::notifyTask(void *param) { LOG_DEBUG("Starting message notify task"); auto _this = static_cast(param); while (true) { // Wait for event xSemaphoreTake(_this->notifySemaphore, portMAX_DELAY); // Read virtio queue and notify all rpmsg clients rproc_virtio_notified(_this->vdev, RSC_NOTIFY_ID_ANY); } } struct remoteproc *RProc::init(remoteproc *rproc, const remoteproc_ops *ops, void *arg) { LOG_DEBUG(""); rproc->ops = ops; rproc->priv = arg; return rproc; } int RProc::handle_rsc(remoteproc *rproc, void *rsc, size_t len) { auto _this = static_cast(rproc->priv); struct fw_rsc_mapping *mapping = static_cast(rsc); if (mapping->type != RSC_MAPPING) { LOG_ERR("Unknown resource type %" PRIu32, mapping->type); return -RPROC_ERR_RSC_TAB_NS; } for (uint32_t i = 0; i < mapping->num_ranges; ++i) { const fw_rsc_map_range *range = &mapping->range[i]; if (range->len == 0) { LOG_DEBUG("Ignored zero length memory map range[%" PRIu32 "]", i); continue; } setupRProcMem(*rproc, range->pa, range->da, range->len, _this->mems[i], _this->regions[i]); } return 0; } void RProc::remove(remoteproc *rproc) { LOG_DEBUG(""); } int RProc::notify(remoteproc *rproc, uint32_t id) { LOG_DEBUG(""); auto *_this = static_cast(rproc->priv); _this->mailbox.sendMessage(); return 0; } /***************************************************************************** * Rpmsg *****************************************************************************/ Rpmsg::Rpmsg(RProc &rproc, const char *const name) : rvdev({}), rdev(), endpoint({}) { struct virtio_device *vdev = rproc.getVDev(); if (vdev->vrings_num != ResourceTable::NUM_VRINGS) { LOG_ERR("Invalid number of vrings"); abort(); } // Vdev can use the same IO region for translations as the vring if (rpmsg_init_vdev(&rvdev, vdev, nullptr, vdev->vrings_info[0].io, nullptr)) { LOG_ERR("Failed to initialize rpmsg vdev"); abort(); } rdev = rpmsg_virtio_get_rpmsg_device(&rvdev); if (!rdev) { LOG_ERR("Failed to get rpmsg dev"); abort(); } int ret = rpmsg_create_ept(&endpoint, rdev, name, RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, endpointCallback, nsUnbindCallback); if (ret != RPMSG_SUCCESS) { LOG_ERR("Failed to create rpmsg endpoint. ret=%d", ret); abort(); } endpoint.priv = static_cast(this); } int Rpmsg::send(void *data, size_t len, uint32_t dst) { LOG_DEBUG("Sending rpmsg. dst=%" PRIu32 ", len=%zu", dst, len); int ret = rpmsg_sendto(&endpoint, data, len, dst); return ret; } void *Rpmsg::physicalToVirtual(metal_phys_addr_t pa) { return metal_io_phys_to_virt(rvdev.shbuf_io, pa); } void Rpmsg::rpmsgNsBind(rpmsg_device *rdev, const char *name, uint32_t dest) { LOG_DEBUG(""); } void Rpmsg::nsUnbindCallback(rpmsg_endpoint *ept) { LOG_DEBUG(""); } int Rpmsg::endpointCallback(rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) { LOG_DEBUG("src=%" PRIX32 ", len=%zu", src, len); auto _this = static_cast(priv); _this->handleMessage(data, len, src); return 0; } int Rpmsg::handleMessage(void *data, size_t len, uint32_t src) { LOG_DEBUG("Receiving rpmsg. src=%" PRIu32 ", len=%zu", src, len); auto c = static_cast(data); for (size_t i = 0; i < len; i++) { printf("%c", c[i]); } printf("\n"); return 0; }