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