Add resource table entry for address translation

To avoid having to use a hardcoded memory map to translate between the
Linux physical addresses and device addresses, a new entry type has been
added to the resource table where the host can provide the memory map to
use for the translation.

Change-Id: I668bba3aeac27c358647c969c5504326e1c91d24
Signed-off-by: Mikael Olsson <mikael.olsson@arm.com>
diff --git a/applications/message_handler_openamp/remoteproc.cpp b/applications/message_handler_openamp/remoteproc.cpp
index f355634..8fda69b 100644
--- a/applications/message_handler_openamp/remoteproc.cpp
+++ b/applications/message_handler_openamp/remoteproc.cpp
@@ -1,6 +1,5 @@
 /*
  * SPDX-FileCopyrightText: Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
- *
  * SPDX-License-Identifier: Apache-2.0
  *
  * Licensed under the Apache License, Version 2.0 (the License); you may
@@ -26,66 +25,39 @@
 
 #include <ethosu_log.h>
 
-/*****************************************************************************
- * MetalIO
- *****************************************************************************/
+namespace {
+void setupRProcMem(remoteproc &rproc,
+                   metal_phys_addr_t pa,
+                   metal_phys_addr_t da,
+                   size_t size,
+                   remoteproc_mem &mem,
+                   metal_io_region &region) {
 
-extern "C" {
-
-__attribute__((weak)) void *ethosu_phys_to_virt(const uint64_t pa) {
-    return reinterpret_cast<void *>(pa);
+    remoteproc_init_mem(&mem, nullptr, pa, da, size, &region);
+    metal_io_init(&region, (void *)da, &mem.pa, size, -1, 0, nullptr);
+    remoteproc_add_mem(&rproc, &mem);
 }
-}
-
-MetalIO::MetalIO() :
-    ops{.read           = nullptr,
-        .write          = nullptr,
-        .block_read     = nullptr,
-        .block_write    = nullptr,
-        .block_set      = nullptr,
-        .close          = nullptr,
-        .offset_to_phys = nullptr,
-        .phys_to_offset = physToOffset} {
-    remoteproc_init_mem(&mem, "shm", 0, 0, 0xffffffff, &region);
-
-    metal_io_init(&region,
-                  reinterpret_cast<void *>(0), /* virt */
-                  &mem.pa,                     /* physmap */
-                  0xffffffff,                  /* size */
-                  -1L,                         /* pagemask */
-                  0,                           /* attributes */
-                  &ops);                       /* ops */
-}
-
-remoteproc_mem *MetalIO::operator&() {
-    return &mem;
-}
-
-unsigned long MetalIO::physToOffset(metal_io_region *io, metal_phys_addr_t pa) {
-    auto offset = reinterpret_cast<unsigned long>(ethosu_phys_to_virt(pa));
-    LOG_DEBUG("Translate PA to offset. pa=%lx, offset=%lx", pa, offset);
-    return offset;
-}
+}; // namespace
 
 /*****************************************************************************
  * RProc
  *****************************************************************************/
 
-RProc::RProc(Mailbox::Mailbox &_mailbox, resource_table &table, size_t tableSize, MetalIO &_mem) :
-    mailbox(_mailbox), mem(_mem),
+RProc::RProc(Mailbox::Mailbox &_mailbox, resource_table &table, size_t tableSize) :
+    mailbox(_mailbox),
     ops{
-        .init       = init,    // initialize the remoteproc instance
-        .remove     = remove,  // remove the remoteproc instance
-        .mmap       = nullptr, // memory mapped the memory with physical address as input
-        .handle_rsc = nullptr, // handle the vendor specific resource
-        .config     = nullptr, // configure the remoteproc to make it ready to load and run executable
-        .start      = nullptr, // kick the remoteproc to run application
+        .init       = init,       // initialize the remoteproc instance
+        .remove     = remove,     // remove the remoteproc instance
+        .mmap       = nullptr,    // memory mapped the memory with physical address as input
+        .handle_rsc = handle_rsc, // handle the vendor specific resource
+        .config     = nullptr,    // configure the remoteproc to make it ready to load and run executable
+        .start      = nullptr,    // kick the remoteproc to run application
         .stop = nullptr, // stop the remoteproc from running application, the resource such as memory may not be off.
         .shutdown = nullptr, // shutdown the remoteproc and release its resources.
         .notify   = notify,  // notify the remote
         .get_mem  = nullptr, // get remoteproc memory I/O region.
     },
-    vdev(nullptr), notifySemaphore(xSemaphoreCreateBinary()) {
+    vdev(nullptr), mems(), regions(), notifySemaphore(xSemaphoreCreateBinary()) {
     mailbox.registerCallback(mailboxCallback, static_cast<void *>(this));
 
     if (!remoteproc_init(&rproc, &ops, this)) {
@@ -93,6 +65,12 @@
         abort();
     }
 
+    // Setup memory region for resource table
+    const metal_phys_addr_t rsc_addr = reinterpret_cast<metal_phys_addr_t>(&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);
@@ -148,15 +126,33 @@
 struct remoteproc *RProc::init(remoteproc *rproc, const remoteproc_ops *ops, void *arg) {
     LOG_DEBUG("");
 
-    auto _this = static_cast<RProc *>(arg);
-
     rproc->ops  = ops;
     rproc->priv = arg;
-    remoteproc_add_mem(rproc, &_this->mem);
 
     return rproc;
 }
 
+int RProc::handle_rsc(remoteproc *rproc, void *rsc, size_t len) {
+    auto _this                     = static_cast<RProc *>(rproc->priv);
+    struct fw_rsc_mapping *mapping = static_cast<fw_rsc_mapping *>(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("");
 }
@@ -174,14 +170,15 @@
  *****************************************************************************/
 
 Rpmsg::Rpmsg(RProc &rproc, const char *const name) {
+    struct virtio_device *vdev = rproc.getVDev();
 
-    metal_io_region *region = remoteproc_get_io_with_name(rproc.getRProc(), "shm");
-    if (!region) {
-        LOG_ERR("Failed to get shared mem region");
+    if (vdev->vrings_num != ResourceTable::NUM_VRINGS) {
+        LOG_ERR("Invalid number of vrings");
         abort();
     }
 
-    if (rpmsg_init_vdev(&rvdev, rproc.getVDev(), nullptr, region, nullptr)) {
+    // 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();
     }