[PATCH 28/29] hw/core: Add Remote Port attachment helpers

Ruslan Ruslichenko posted 29 patches 1 day, 11 hours ago
[PATCH 28/29] hw/core: Add Remote Port attachment helpers
Posted by Ruslan Ruslichenko 1 day, 11 hours ago
From: Mirsad Ostrakovic <mirsad_ostrakovic@epam.com>

Introduce helper functions to dynamically attach and detach Remote Port
devices to an adaptor.

This patch adds the logic to:
- Connect devices to an adaptor via QOM links ('rp_device_attach').
- Parse command-line options ('rp_device_add') to automatically wire up
  devices using 'rp-adaptor' and 'rp-chan' properties.

Signed-off-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Signed-off-by: Takahiro Nakata <takahiro.nakata.wr@renesas.com>
Signed-off-by: Mirsad Ostrakovic <mirsad_ostrakovic@epam.com>
Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
---
 hw/core/meson.build           |   1 +
 hw/core/remote-port-qdev.c    | 181 ++++++++++++++++++++++++++++++++++
 include/hw/core/remote-port.h |  27 +++++
 3 files changed, 209 insertions(+)
 create mode 100644 hw/core/remote-port-qdev.c

diff --git a/hw/core/meson.build b/hw/core/meson.build
index 7013638fcf..4638106e92 100644
--- a/hw/core/meson.build
+++ b/hw/core/meson.build
@@ -35,6 +35,7 @@ system_ss.add(when: 'CONFIG_REMOTE_PORT', if_true: files(
   'remote-port-gpio.c',
   'remote-port-stream.c',
   'remote-port-ats.c',
+  'remote-port-qdev.c'
 ))
 
 system_ss.add(files(
diff --git a/hw/core/remote-port-qdev.c b/hw/core/remote-port-qdev.c
new file mode 100644
index 0000000000..35c9a6790d
--- /dev/null
+++ b/hw/core/remote-port-qdev.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * QEMU remote attach
+ *
+ * Copyright (c) 2013 Xilinx Inc
+ * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
+ *
+ * This code is licensed under the GNU GPL.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/sysbus.h"
+#include "monitor/monitor.h"
+#include "monitor/qdev.h"
+#include "system/arch_init.h"
+#include "qapi/error.h"
+#include "qemu/config-file.h"
+#include "qemu/error-report.h"
+#include "qemu/help_option.h"
+#include "qemu/cutils.h"
+#include "qemu/option.h"
+
+#include "hw/core/remote-port.h"
+
+/* RP helper function to attach a device to an adaptor.  */
+void rp_device_attach(Object *adaptor, Object *dev,
+                      int rp_nr, int dev_nr,
+                      Error **errp)
+{
+    Error *err = NULL;
+    uint32_t nr_devs;
+    char *name;
+    int i;
+
+    assert(adaptor);
+    assert(dev);
+
+    /* Verify that the adaptor is of Remote Port type.  */
+    if (!object_dynamic_cast(adaptor, TYPE_REMOTE_PORT)) {
+        error_setg(errp, "%s is not a Remote-Port adaptor!",
+                   object_get_canonical_path(adaptor));
+        return;
+    }
+
+    name = g_strdup_printf("rp-adaptor%d", rp_nr);
+    object_property_set_link(dev, name, adaptor, &err);
+    g_free(name);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    name = g_strdup_printf("rp-chan%d", rp_nr);
+    object_property_set_int(dev, name, dev_nr, &err);
+    g_free(name);
+    if (err != NULL
+        && !object_dynamic_cast(dev, TYPE_REMOTE_PORT_DEVICE)) {
+        /*
+         * RP devices that only receive requests may not need to
+         * know their channel/dev number. If not, treat this as
+         * an error.
+         */
+        error_propagate(errp, err);
+        return;
+    }
+    err = NULL;
+
+    nr_devs = object_property_get_int(dev, "nr-devs", &err);
+    if (err) {
+        nr_devs = 1;
+        err = NULL;
+    }
+
+    /* Multi-channel devs use consecutive numbering.  */
+    for (i = 0; i < nr_devs; i++) {
+        name = g_strdup_printf("remote-port-dev%d", dev_nr + i);
+        object_property_set_link(adaptor, name, dev, &err);
+        g_free(name);
+        if (err != NULL) {
+            error_propagate(errp, err);
+            return;
+        }
+    }
+}
+
+/* RP helper function to detach a device to an adaptor.  */
+void rp_device_detach(Object *adaptor, Object *dev,
+                      int rp_nr, int dev_nr,
+                      Error **errp)
+{
+    Error *err = NULL;
+    uint32_t nr_devs;
+    char *name;
+    int i;
+
+    assert(adaptor);
+    assert(dev);
+
+    name = g_strdup_printf("rp-adaptor%d", rp_nr);
+    object_property_set_link(dev, name, NULL, NULL);
+    g_free(name);
+
+    nr_devs = object_property_get_int(dev, "nr-devs", &err);
+    if (err) {
+        nr_devs = 1;
+        err = NULL;
+    }
+
+    for (i = 0; i < nr_devs; i++) {
+        name = g_strdup_printf("remote-port-dev%d", dev_nr + i);
+        object_property_set_link(adaptor, name, NULL, &err);
+        g_free(name);
+        if (err != NULL) {
+            error_propagate(errp, err);
+            return;
+        }
+    }
+}
+
+/* Scan for remote-port links to be setup.  */
+bool rp_device_add(const QDict *opts, DeviceState *dev, Error **errp)
+{
+    Error *err = NULL;
+    Object *adaptor;
+    bool ambiguous;
+    const char *path;
+    char *name;
+    int i;
+
+    /*
+     * Find the adaptor this remote-port device is connected to.
+     * At the moment, we only support one adaptor per device.
+     */
+    name = g_strdup_printf("rp-adaptor%d", 0);
+    path = qdict_get_try_str(opts, name);
+    g_free(name);
+    if (!path) {
+        /* This is not a remote-port device. Treat as success.  */
+        return true;
+    }
+    adaptor = object_resolve_path(path, &ambiguous);
+    if (!adaptor) {
+        error_setg(errp, "Did not find rp adaptor %s!", path);
+        return false;
+    }
+
+    /*
+     * Loop through the channels this device provides and attach
+     * them to the adaptor.
+     */
+    for (i = 0; i < INT_MAX; i++) {
+        unsigned long dev_nr;
+        const char *dev_nr_str;
+
+        name = g_strdup_printf("rp-chan%d", i);
+        dev_nr_str = qdict_get_try_str(opts, name);
+        g_free(name);
+
+        if (!dev_nr_str) {
+            if (i == 0) {
+                /* At least one channel must be provided.  */
+                error_setg(errp, "Did not find rp-chan%d!", i);
+                return false;
+            }
+            return true;
+        }
+
+        if (qemu_strtoul(dev_nr_str, NULL, 0, &dev_nr)) {
+            error_setg(errp, "Invalid rp-chan%d!", i);
+            return false;
+        }
+
+        /* Now, attach the device to the adaptor.  */
+        rp_device_attach(adaptor, OBJECT(dev), 0, dev_nr, &err);
+        if (err != NULL) {
+            error_propagate(errp, err);
+            return false;
+        }
+    }
+    return true;
+}
diff --git a/include/hw/core/remote-port.h b/include/hw/core/remote-port.h
index 172c4b6204..252230961b 100644
--- a/include/hw/core/remote-port.h
+++ b/include/hw/core/remote-port.h
@@ -134,6 +134,33 @@ struct RemotePort {
     RemotePortDevice *devs[REMOTE_PORT_MAX_DEVS];
 };
 
+/**
+ * rp_device_attach:
+ * @adaptor: The adaptor onto which to attach the device
+ * @dev: The device to be attached to the adaptor
+ * @rp_nr: The remote-port adaptor nr. A device may attach to multiple
+ *         adaptors.
+ * @dev_nr: The device/channel number to bind the device to.
+ * @errp: returns an error if this function fails
+ *
+ * Attaches a device onto an adaptor and binds it to a device number.
+ */
+void rp_device_attach(Object *adaptor, Object *dev,
+                      int rp_nr, int dev_nr,
+                      Error **errp);
+void rp_device_detach(Object *adaptor, Object *dev,
+                      int rp_nr, int dev_nr,
+                      Error **errp);
+/**
+ * rp_device_add
+ * @opts:  qdev opts created by the qdev subsystem
+ * @dev: The device to be connected
+ * @errp: Returns an error if the function fails
+ *
+ * Function used in qdev-monitor.c to connect remote port devices.
+ * Returns teue on success and false on failure.
+ */
+bool rp_device_add(const QDict *opts, DeviceState *dev, Error **errp);
 
 void rp_rsp_mutex_lock(RemotePort *s);
 void rp_rsp_mutex_unlock(RemotePort *s);
-- 
2.43.0