Kristofer Jonsson | 3f5510f | 2023-02-08 14:23:00 +0100 | [diff] [blame] | 1 | /* |
| 2 | * SPDX-FileCopyrightText: Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com> |
| 3 | * |
| 4 | * SPDX-License-Identifier: Apache-2.0 |
| 5 | * |
| 6 | * Licensed under the Apache License, Version 2.0 (the License); you may |
| 7 | * not use _this file except in compliance with the License. |
| 8 | * You may obtain a copy of the License at |
| 9 | * |
| 10 | * www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, software |
| 13 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT |
| 14 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | * See the License for the specific language governing permissions and |
| 16 | * limitations under the License. |
| 17 | */ |
| 18 | |
| 19 | /***************************************************************************** |
| 20 | * Includes |
| 21 | *****************************************************************************/ |
| 22 | |
| 23 | #include "remoteproc.hpp" |
| 24 | |
| 25 | #include <cinttypes> |
| 26 | |
| 27 | #include <ethosu_log.h> |
| 28 | |
| 29 | /***************************************************************************** |
| 30 | * MetalIO |
| 31 | *****************************************************************************/ |
| 32 | |
| 33 | extern "C" { |
| 34 | |
| 35 | __attribute__((weak)) void *ethosu_phys_to_virt(const uint64_t pa) { |
| 36 | return reinterpret_cast<void *>(pa); |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | MetalIO::MetalIO() : |
| 41 | ops{.read = nullptr, |
| 42 | .write = nullptr, |
| 43 | .block_read = nullptr, |
| 44 | .block_write = nullptr, |
| 45 | .block_set = nullptr, |
| 46 | .close = nullptr, |
| 47 | .offset_to_phys = nullptr, |
| 48 | .phys_to_offset = physToOffset} { |
| 49 | remoteproc_init_mem(&mem, "shm", 0, 0, 0xffffffff, ®ion); |
| 50 | |
| 51 | metal_io_init(®ion, |
| 52 | reinterpret_cast<void *>(0), /* virt */ |
| 53 | &mem.pa, /* physmap */ |
| 54 | 0xffffffff, /* size */ |
| 55 | -1L, /* pagemask */ |
| 56 | 0, /* attributes */ |
| 57 | &ops); /* ops */ |
| 58 | } |
| 59 | |
| 60 | remoteproc_mem *MetalIO::operator&() { |
| 61 | return &mem; |
| 62 | } |
| 63 | |
| 64 | unsigned long MetalIO::physToOffset(metal_io_region *io, metal_phys_addr_t pa) { |
| 65 | auto offset = reinterpret_cast<unsigned long>(ethosu_phys_to_virt(pa)); |
| 66 | LOG_DEBUG("Translate PA to offset. pa=%lx, offset=%lx", pa, offset); |
| 67 | return offset; |
| 68 | } |
| 69 | |
| 70 | /***************************************************************************** |
| 71 | * RProc |
| 72 | *****************************************************************************/ |
| 73 | |
| 74 | RProc::RProc(Mailbox::Mailbox &_mailbox, resource_table &table, size_t tableSize, MetalIO &_mem) : |
| 75 | mailbox(_mailbox), mem(_mem), |
| 76 | ops{ |
| 77 | .init = init, // initialize the remoteproc instance |
| 78 | .remove = remove, // remove the remoteproc instance |
| 79 | .mmap = nullptr, // memory mapped the memory with physical address as input |
| 80 | .handle_rsc = nullptr, // handle the vendor specific resource |
| 81 | .config = nullptr, // configure the remoteproc to make it ready to load and run executable |
| 82 | .start = nullptr, // kick the remoteproc to run application |
| 83 | .stop = nullptr, // stop the remoteproc from running application, the resource such as memory may not be off. |
| 84 | .shutdown = nullptr, // shutdown the remoteproc and release its resources. |
| 85 | .notify = notify, // notify the remote |
| 86 | .get_mem = nullptr, // get remoteproc memory I/O region. |
| 87 | }, |
| 88 | vdev(nullptr), notifySemaphore(xSemaphoreCreateBinary()) { |
| 89 | mailbox.registerCallback(mailboxCallback, static_cast<void *>(this)); |
| 90 | |
| 91 | if (!remoteproc_init(&rproc, &ops, this)) { |
| 92 | LOG_ERR("Failed to intialize remoteproc"); |
| 93 | abort(); |
| 94 | } |
| 95 | |
| 96 | int ret = remoteproc_set_rsc_table(&rproc, &table, tableSize); |
| 97 | if (ret) { |
| 98 | LOG_ERR("Failed to set resource table. ret=%d", ret); |
| 99 | abort(); |
| 100 | } |
| 101 | |
| 102 | vdev = remoteproc_create_virtio(&rproc, 0, VIRTIO_DEV_DEVICE, nullptr); |
| 103 | if (!vdev) { |
| 104 | LOG_ERR("Failed to create vdev"); |
| 105 | abort(); |
| 106 | } |
| 107 | |
| 108 | BaseType_t taskret = xTaskCreate(notifyTask, "notifyTask", 1024, this, 2, ¬ifyHandle); |
| 109 | if (taskret != pdPASS) { |
| 110 | LOG_ERR("Failed to create remoteproc notify task"); |
| 111 | abort(); |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | RProc::~RProc() { |
| 116 | mailbox.deregisterCallback(mailboxCallback, static_cast<void *>(this)); |
| 117 | vTaskDelete(notifyHandle); |
| 118 | } |
| 119 | |
| 120 | remoteproc *RProc::getRProc() { |
| 121 | return &rproc; |
| 122 | } |
| 123 | |
| 124 | virtio_device *RProc::getVDev() { |
| 125 | return vdev; |
| 126 | } |
| 127 | |
| 128 | void RProc::mailboxCallback(void *userArg) { |
| 129 | auto _this = static_cast<RProc *>(userArg); |
| 130 | |
| 131 | xSemaphoreGiveFromISR(_this->notifySemaphore, nullptr); |
| 132 | } |
| 133 | |
| 134 | void RProc::notifyTask(void *param) { |
| 135 | LOG_DEBUG("Starting message notify task"); |
| 136 | |
| 137 | auto _this = static_cast<RProc *>(param); |
| 138 | |
| 139 | while (true) { |
| 140 | // Wait for event |
| 141 | xSemaphoreTake(_this->notifySemaphore, portMAX_DELAY); |
| 142 | |
| 143 | // Read virtio queue and notify all rpmsg clients |
| 144 | rproc_virtio_notified(_this->vdev, RSC_NOTIFY_ID_ANY); |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | struct remoteproc *RProc::init(remoteproc *rproc, const remoteproc_ops *ops, void *arg) { |
| 149 | LOG_DEBUG(""); |
| 150 | |
| 151 | auto _this = static_cast<RProc *>(arg); |
| 152 | |
| 153 | rproc->ops = ops; |
| 154 | rproc->priv = arg; |
| 155 | remoteproc_add_mem(rproc, &_this->mem); |
| 156 | |
| 157 | return rproc; |
| 158 | } |
| 159 | |
| 160 | void RProc::remove(remoteproc *rproc) { |
| 161 | LOG_DEBUG(""); |
| 162 | } |
| 163 | |
| 164 | int RProc::notify(remoteproc *rproc, uint32_t id) { |
| 165 | LOG_DEBUG(""); |
| 166 | |
| 167 | auto *_this = static_cast<RProc *>(rproc->priv); |
| 168 | _this->mailbox.sendMessage(); |
| 169 | return 0; |
| 170 | } |
| 171 | |
| 172 | /***************************************************************************** |
| 173 | * Rpmsg |
| 174 | *****************************************************************************/ |
| 175 | |
| 176 | Rpmsg::Rpmsg(RProc &rproc, const char *const name) { |
| 177 | |
| 178 | metal_io_region *region = remoteproc_get_io_with_name(rproc.getRProc(), "shm"); |
| 179 | if (!region) { |
| 180 | LOG_ERR("Failed to get shared mem region"); |
| 181 | abort(); |
| 182 | } |
| 183 | |
| 184 | if (rpmsg_init_vdev(&rvdev, rproc.getVDev(), nullptr, region, nullptr)) { |
| 185 | LOG_ERR("Failed to initialize rpmsg vdev"); |
| 186 | abort(); |
| 187 | } |
| 188 | |
| 189 | rdev = rpmsg_virtio_get_rpmsg_device(&rvdev); |
| 190 | if (!rdev) { |
| 191 | LOG_ERR("Failed to get rpmsg dev"); |
| 192 | abort(); |
| 193 | } |
| 194 | |
| 195 | int ret = |
| 196 | rpmsg_create_ept(&endpoint, rdev, name, RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, endpointCallback, nsUnbindCallback); |
| 197 | if (ret != RPMSG_SUCCESS) { |
| 198 | LOG_ERR("Failed to create rpmsg endpoint. ret=%d", ret); |
| 199 | abort(); |
| 200 | } |
| 201 | |
| 202 | endpoint.priv = static_cast<void *>(this); |
| 203 | } |
| 204 | |
| 205 | int Rpmsg::send(void *data, size_t len, uint32_t dst) { |
| 206 | LOG_DEBUG("Sending rpmsg. dst=%" PRIu32 ", len=%zu", dst, len); |
| 207 | |
| 208 | int ret = rpmsg_sendto(&endpoint, data, len, dst); |
| 209 | return ret; |
| 210 | } |
| 211 | |
| 212 | void *Rpmsg::physicalToVirtual(metal_phys_addr_t pa) { |
| 213 | return metal_io_phys_to_virt(rvdev.shbuf_io, pa); |
| 214 | } |
| 215 | |
| 216 | void Rpmsg::rpmsgNsBind(rpmsg_device *rdev, const char *name, uint32_t dest) { |
| 217 | LOG_DEBUG(""); |
| 218 | } |
| 219 | |
| 220 | void Rpmsg::nsUnbindCallback(rpmsg_endpoint *ept) { |
| 221 | LOG_DEBUG(""); |
| 222 | } |
| 223 | |
| 224 | int Rpmsg::endpointCallback(rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) { |
| 225 | LOG_DEBUG("src=%" PRIX32 ", len=%zu", src, len); |
| 226 | |
| 227 | auto _this = static_cast<Rpmsg *>(priv); |
| 228 | _this->handleMessage(data, len, src); |
| 229 | |
| 230 | return 0; |
| 231 | } |
| 232 | |
| 233 | int Rpmsg::handleMessage(void *data, size_t len, uint32_t src) { |
| 234 | LOG_DEBUG("Receiving rpmsg. src=%" PRIu32 ", len=%zu", src, len); |
| 235 | |
| 236 | auto c = static_cast<char *>(data); |
| 237 | for (size_t i = 0; i < len; i++) { |
| 238 | printf("%c", c[i]); |
| 239 | } |
| 240 | printf("\n"); |
| 241 | |
| 242 | return 0; |
| 243 | } |