All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 1/1] x86/vm86: fix vm86 struct leak on copy_from_user() failure
From: Borislav Petkov @ 2026-06-24 17:40 UTC (permalink / raw)
  To: fffsqian
  Cc: Thomas Gleixner, Ingo Molnar, Dave Hansen, x86, hpa, Kees Cook,
	Andy Lutomirski, Brian Gerst, linux-gpio, Qingshuang Fu
In-Reply-To: <20260624092629.271618-1-fffsqian@163.com>

On Wed, Jun 24, 2026 at 05:26:29PM +0800, fffsqian@163.com wrote:
> diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
> index b4c1cabc7a4b..cde077f2c97e 100644
> --- a/arch/x86/kernel/vm86_32.c
> +++ b/arch/x86/kernel/vm86_32.c
> @@ -202,7 +202,8 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
>  	struct vm86 *vm86 = tsk->thread.vm86;
>  	struct kernel_vm86_regs vm86regs;
>  	struct pt_regs *regs = current_pt_regs();
> -	unsigned long err = 0;
> +	bool newly_allocated = false;

What for?

Take a look at kfree()'s implementation.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

^ permalink raw reply

* Re: [PATCH] Makefile: avoid 0 as NULL pointer constant
From: Petr Lautrbach @ 2026-06-24 17:40 UTC (permalink / raw)
  To: selinux, Stephen Smalley, cgzones
In-Reply-To: <CAEjxPJ4m7__fzUnv2KP2hqLAzNvEOqn_xkH_oEMxP7hfWpHdkA@mail.gmail.com>

Stephen Smalley <stephen.smalley.work@gmail.com> writes:

> On Tue, Jun 23, 2026 at 9:40 AM Christian Göttsche
> <cgoettsche@seltendoof.de> wrote:
>>
>> From: Christian Göttsche <cgzones@googlemail.com>
>>
>> fts_close(3) takes a pointer as argument; use `(void*)0` instead of pure
>> `0` to please building with `-Wzero-as-null-pointer-constant`. Avoid
>> using NULL to not require <stddef.h>.
>>
>> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
>
> Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>

Merged.

>> ---
>>  Makefile | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/Makefile b/Makefile
>> index 0e465f94..ae8586c6 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -29,7 +29,7 @@ endif
>>
>>  # check for fts_* availability
>>  H := \#
>> -ifneq (yes,$(shell printf '${H}include <fts.h>\nint main(void){return fts_close(0);}' | $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Werror=implicit-function-declaration -x c -o /dev/null - >/dev/null 2>&1 && echo yes))
>> +ifneq (yes,$(shell printf '${H}include <fts.h>\nint main(void){return fts_close((void*)0);}' | $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Werror=implicit-function-declaration -x c -o /dev/null - >/dev/null 2>&1 && echo yes))
>>  export FTS_LDLIBS := -lfts
>>  endif
>>
>> --
>> 2.53.0
>>
>>


^ permalink raw reply

* [PATCH v5 32/35] monitor: add support for auto-deleting monitors upon close
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

The default monitor is usually a long lived object that will exist for
the entire lifetime of the VM. A monitor can only service a single
client at a time though, and so it might be desirable to hotplug
additional monitors at runtime for specific tasks. If doing that,
however, there is a need to remove the monitor when it is no longer
needed.

Allowing a client to run "object-del" against its own monitor adds
complex edge cases, as it would be desirable to send the QMP response
despite the monitor sending it being deleted. Doing "object-del" alone
will also result in orphaning a character device backend instance, as
there is no opportunity to run the companion "chardev-del" command.

A simpler way to ensure cleanup is to add the concept of auto-deleting
monitor objects. Specifically when the "CHR_EVENT_CLOSED" event is
emitted, the equivalent of "object-del" + "chardev-del" can be run
internally. Since the transient client has already droppped its
monitor connection, there is no synchronization to be concerned about.

This is implemented via a new "close-action=none|delete" property on
the 'monitor-qmp' object. This concept could be extended with further
actions in future, for example:

 * close-action=shutdown - graceful guest shutdown
 * close-action=terminate - immediate guest poweroff
 * close-action=stop - pause guest CPUs while the monitor is not
                       connected to any client

This is left as an exercise for future interested contributors.

Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/monitor-internal.h                    |  3 +
 monitor/qmp.c                                 | 75 +++++++++++++++++
 qapi/qom.json                                 | 21 ++++-
 .../generic/test_monitor_hotplug.py           | 83 ++++++++++++++++++-
 4 files changed, 177 insertions(+), 5 deletions(-)

diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 5522e05464..23829f32f9 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -28,6 +28,7 @@
 #include "chardev/char-fe.h"
 #include "monitor/monitor.h"
 #include "qapi/qapi-types-control.h"
+#include "qapi/qapi-types-qom.h"
 #include "qapi/qmp-registry.h"
 #include "qobject/json-parser.h"
 #include "qemu/readline.h"
@@ -178,7 +179,9 @@ struct MonitorQMP {
     Monitor parent_obj;
     JSONMessageParser parser;
     bool pretty;
+    MonitorQMPCloseAction close_action;
     bool setup_pending; /* iothread BH has not yet set up chardev handlers */
+    bool delete_pending; /* close_action has started 'delete' process */
     /*
      * When a client connects, we're in capabilities negotiation mode.
      * @commands is &qmp_cap_negotiation_commands then.  When command
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 5301927f09..1057b0d12b 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -28,6 +28,7 @@
 #include "monitor-internal.h"
 #include "qapi/error.h"
 #include "qapi/qapi-commands-control.h"
+#include "qapi/qapi-commands-char.h"
 #include "qobject/qdict.h"
 #include "qobject/qjson.h"
 #include "qobject/qlist.h"
@@ -103,6 +104,20 @@ static void monitor_qmp_set_pretty(Object *obj, bool val, Error **errp)
     mon->pretty = val;
 }
 
+static int monitor_qmp_get_close_action(Object *obj, Error **errp)
+{
+    MonitorQMP *mon = MONITOR_QMP(obj);
+
+    return mon->close_action;
+}
+
+static void monitor_qmp_set_close_action(Object *obj, int val, Error **errp)
+{
+    MonitorQMP *mon = MONITOR_QMP(obj);
+
+    mon->close_action = val;
+}
+
 static void monitor_qmp_emit_event(Monitor *mon, QAPIEvent event, QDict *qdict);
 static bool monitor_qmp_requires_iothread(const Monitor *mon);
 static void monitor_qmp_complete(UserCreatable *uc, Error **errp);
@@ -117,6 +132,11 @@ static void monitor_qmp_class_init(ObjectClass *cls, const void *data)
     object_class_property_add_bool(cls, "pretty",
                                    monitor_qmp_get_pretty,
                                    monitor_qmp_set_pretty);
+    object_class_property_add_enum(cls, "close-action",
+                                   "MonitorQMPCloseAction",
+                                   &MonitorQMPCloseAction_lookup,
+                                   monitor_qmp_get_close_action,
+                                   monitor_qmp_set_close_action);
 
     moncls->emit_event = monitor_qmp_emit_event;
     moncls->requires_iothread = monitor_qmp_requires_iothread;
@@ -550,11 +570,45 @@ static QDict *qmp_greeting(MonitorQMP *mon)
         ver, cap_list);
 }
 
+static void monitor_qmp_self_delete_bh(void *opaque)
+{
+    MonitorQMP *mon = opaque;
+    g_autofree char *mon_id = object_property_get_child_name(
+        object_get_objects_root(), OBJECT(mon));
+    g_autofree char *chardev_id = g_strdup(mon->parent_obj.chardev_id);
+    Error *local_error = NULL;
+
+    if (!mon_id) {
+        /* Another monitor raced & ran 'object-del' on 'mon'
+         * before this BH got scheduled, so we have a ref on
+         * mon but it is already unparented.
+         */
+        object_unref(mon);
+        return;
+    }
+
+    user_creatable_del(mon_id, &local_error);
+    object_unref(mon);
+    if (local_error != NULL) {
+        error_report_err(local_error);
+    } else {
+        qmp_chardev_remove(chardev_id, NULL);
+    }
+}
+
 static void monitor_qmp_event(void *opaque, QEMUChrEvent event)
 {
     QDict *data;
     MonitorQMP *mon = opaque;
 
+    /* Protect against race if a client drops & quickly
+     * reconnects - we'll have the delete BH scheduled
+     * so must not honour a new open request
+     */
+    if (mon->delete_pending) {
+        return;
+    }
+
     switch (event) {
     case CHR_EVENT_OPENED:
         WITH_QEMU_LOCK_GUARD(&mon->parent_obj.mon_lock) {
@@ -577,6 +631,27 @@ static void monitor_qmp_event(void *opaque, QEMUChrEvent event)
         json_message_parser_init(&mon->parser, handle_qmp_command,
                                  mon, NULL);
         monitor_fdsets_cleanup();
+        switch (mon->close_action) {
+        case MONITOR_QMP_CLOSE_ACTION_NONE:
+            break; /* nada */
+        case MONITOR_QMP_CLOSE_ACTION_DELETE:
+            mon->delete_pending = true;
+            /*
+             * Do NOT run in the AIO context associated with the
+             * monitor. We need to run in the default AIO context
+             * which is the same context in which 'qmp_object_del'
+             * will execute
+             *
+             * Hold an extra ref in case a separate monitor races
+             * with the BH by processing an explicit 'object-del'
+             */
+            object_ref(mon);
+            aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                                    monitor_qmp_self_delete_bh, mon);
+            break;
+        default:
+            g_assert_not_reached();
+        }
         break;
     case CHR_EVENT_BREAK:
     case CHR_EVENT_MUX_IN:
diff --git a/qapi/qom.json b/qapi/qom.json
index 6affb70a59..b4c49a2e8b 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -1213,18 +1213,37 @@
   'base': 'MonitorProperties',
   'data': { '*readline': 'bool' } }
 
+
+##
+# @MonitorQMPCloseAction:
+#
+# Action to take when the character device backend is
+# closed.
+#
+# @none: take no action (the default)
+# @delete: delete both the 'monitor-qmp' object and its associated
+#          character device backend object
+#
+# Since 11.1
+##
+{ 'enum' : 'MonitorQMPCloseAction',
+  'data': ['none', 'delete'] }
+
 ##
 # @MonitorQMPProperties:
 #
 # Properties for the QMP monitor
 #
 # @pretty: whether to pretty print JSON responses (default: disabled)
+# @close-action: action to take when the character device backend
+#                is closed (default: none)
 #
 # Since: 11.1
 ##
 { 'struct': 'MonitorQMPProperties',
   'base': 'MonitorProperties',
-  'data': { '*pretty': 'bool' } }
+  'data': { '*pretty': 'bool',
+            '*close-action': 'MonitorQMPCloseAction' } }
 
 ##
 # @ObjectType:
diff --git a/tests/functional/generic/test_monitor_hotplug.py b/tests/functional/generic/test_monitor_hotplug.py
index 55af8a238f..86092e781c 100755
--- a/tests/functional/generic/test_monitor_hotplug.py
+++ b/tests/functional/generic/test_monitor_hotplug.py
@@ -25,7 +25,7 @@ def setUp(self):
         sock_dir = self.socket_dir()
         self._sock_path = os.path.join(sock_dir.name, 'hotplug.sock')
 
-    def _add_monitor(self):
+    def _add_monitor(self, autodelete=False):
         """Create a chardev + monitor and return the socket path."""
         sock = self._sock_path
         self.vm.cmd('chardev-add', id='hotplug-chr', backend={
@@ -39,9 +39,15 @@ def _add_monitor(self):
                 'wait': False,
             }
         })
-        self.vm.cmd('object-add', id='hotplug-mon',
-                    qom_type='monitor-qmp',
-                    chardev='hotplug-chr')
+        if autodelete:
+            self.vm.cmd('object-add', id='hotplug-mon',
+                        qom_type='monitor-qmp',
+                        chardev='hotplug-chr',
+                        close_action='delete')
+        else:
+            self.vm.cmd('object-add', id='hotplug-mon',
+                        qom_type='monitor-qmp',
+                        chardev='hotplug-chr')
         return sock
 
     def _remove_monitor(self):
@@ -118,6 +124,75 @@ def test_self_removal(self):
         # Clean up the chardev
         self.vm.cmd('chardev-remove', id='hotplug-chr')
 
+    def test_auto_delete(self):
+        """
+        A dynamically-added monitor configured with 'close-action=delete'
+        should see itself deleted when the client is closed.
+        """
+        self.set_machine('none')
+        self.vm.add_args('-nodefaults')
+        self.vm.launch()
+
+        sock = self._add_monitor(autodelete=True)
+
+        cdevs = [c["label"] for c in self.vm.cmd('query-chardev')]
+        objs = [o["name"] for o in self.vm.cmd('qom-list', path='/objects')]
+        assert ('hotplug-chr' in cdevs)
+        assert ('hotplug-mon' in objs)
+
+        qmp = QEMUMonitorProtocol(sock)
+        greeting = qmp.connect(negotiate=True)
+        self.assertIn('QMP', greeting)
+
+        cdevs = [c["label"] for c in self.vm.cmd('query-chardev')]
+        objs = [o["name"] for o in self.vm.cmd('qom-list', path='/objects')]
+        assert ('hotplug-chr' in cdevs)
+        assert ('hotplug-mon' in objs)
+
+        qmp.close()
+
+        # Wait upto 10 seconds max for chardev to auto-delete, which
+        # is hopefully enough for reliability under high load
+        for i in range(int(10 / 0.2)):
+            cdevs = [c["label"] for c in self.vm.cmd('query-chardev')]
+            if 'hotplug-chr' not in cdevs:
+                break
+            # Wait a little more then try again
+            time.sleep(0.2)
+
+        cdevs = [c["label"] for c in self.vm.cmd('query-chardev')]
+        objs = [o["name"] for o in self.vm.cmd('qom-list', path='/objects')]
+        assert ('hotplug-chr' not in cdevs)
+        assert ('hotplug-mon' not in objs)
+
+    def test_reconnect(self):
+        """
+        A dynamically-added monitor configured without 'close-action'
+        should allow reconnects after the client is closed.
+        """
+        self.set_machine('none')
+        self.vm.add_args('-nodefaults')
+        self.vm.launch()
+
+        sock = self._add_monitor()
+
+        qmp = QEMUMonitorProtocol(sock)
+        qmp.connect(negotiate=True)
+
+        resp = qmp.cmd_obj({'execute': 'query-chardev'})
+        self.assertIn('return', resp)
+
+        qmp.close()
+
+        qmp = QEMUMonitorProtocol(sock)
+        qmp.connect(negotiate=True)
+
+        resp = qmp.cmd_obj({'execute': 'query-chardev'})
+        self.assertIn('return', resp)
+
+        qmp.close()
+        self._remove_monitor()
+
     def test_large_response(self):
         """
         Send a command with a large response (query-qmp-schema) on a
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 24/35] monitor: reject attempts to delete the current monitor
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

From: Christian Brauner <brauner@kernel.org>

If an 'object_del' command for a QMP monitor arrives targetting the
current monitor, reject this request. If the current monitor is
deleted, it will be impossible to send any reply and the client won't
be able to remove the corresponding chardev backend.

Note, it is not possible to rely on checking monitor_cur() because
if 'object_del' is called via human-monitor-command, monitor_cur()
will reflect the temporary HMP, not the QMP target that needs to
be checked.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
[DB: extracted monitor tracking from larger commit; added logic
     to monitor_qmp_prepare_delete to reject request]
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/qmp.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/monitor/qmp.c b/monitor/qmp.c
index 0e1c3eb52b..b0535dec68 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -72,6 +72,9 @@ typedef struct QMPRequest QMPRequest;
 
 QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
 
+/* Monitor being serviced by the dispatcher.  Protected by BQL. */
+static MonitorQMP *qmp_dispatcher_current_mon;
+
 OBJECT_DEFINE_TYPE(MonitorQMP, monitor_qmp, MONITOR_QMP, MONITOR);
 
 static void monitor_qmp_cleanup_req_queue_locked(MonitorQMP *mon);
@@ -369,6 +372,7 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
          */
 
         mon = req_obj->mon;
+        qmp_dispatcher_current_mon = mon;
 
         /*
          * We need to resume the monitor if handle_qmp_command()
@@ -429,6 +433,7 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
         }
 
         qmp_request_free(req_obj);
+        qmp_dispatcher_current_mon = NULL;
     }
     qatomic_set(&qmp_dispatcher_co, NULL);
 }
@@ -573,6 +578,11 @@ static void monitor_qmp_event(void *opaque, QEMUChrEvent event)
     }
 }
 
+static bool monitor_qmp_dispatcher_is_servicing(MonitorQMP *mon)
+{
+    return qmp_dispatcher_current_mon == mon;
+}
+
 static void monitor_qmp_setup_handlers_bh(void *opaque)
 {
     MonitorQMP *mon = opaque;
@@ -646,6 +656,13 @@ static void monitor_qmp_complete(UserCreatable *uc, Error **errp)
 
 static bool monitor_qmp_prepare_delete(UserCreatable *uc, Error **errp)
 {
+    MonitorQMP *qmp = MONITOR_QMP(uc);
+
+    if (monitor_qmp_dispatcher_is_servicing(qmp)) {
+        error_setg(errp, "Cannot delete the current QMP monitor");
+        return false;
+    }
+
     error_setg(errp, "Deleting QMP monitors is not supported");
     return false;
 }
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 20/35] monitor: drop unused monitor_is_qmp method
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

The previous patch dropped the only remaining use of
monitor_is_qmp.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/monitor-internal.h | 9 ---------
 monitor/monitor.c          | 1 -
 2 files changed, 10 deletions(-)

diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index efd21b8912..fe5703af6d 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -134,7 +134,6 @@ struct Monitor {
     char *chardev_id;
     CharFrontend chr;
     int suspend_cnt;            /* Needs to be accessed atomically */
-    bool is_qmp;
 
     char *mon_cpu_path;
     QTAILQ_ENTRY(Monitor) entry;
@@ -197,14 +196,6 @@ struct MonitorQMP {
     GQueue *qmp_requests;
 };
 
-/**
- * Is @mon a QMP monitor?
- */
-static inline bool monitor_is_qmp(const Monitor *mon)
-{
-    return mon->is_qmp;
-}
-
 typedef QTAILQ_HEAD(MonitorList, Monitor) MonitorList;
 extern IOThread *mon_iothread;
 extern Coroutine *qmp_dispatcher_co;
diff --git a/monitor/monitor.c b/monitor/monitor.c
index 15e49d78d7..6ed586fc4f 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -113,7 +113,6 @@ static void monitor_init(Object *obj)
     Monitor *mon = MONITOR(obj);
 
     qemu_mutex_init(&mon->mon_lock);
-    mon->is_qmp = !!object_dynamic_cast(obj, TYPE_MONITOR_QMP);
     mon->outbuf = g_string_new(NULL);
 }
 
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 06/35] monitor: add 'chardev' property to Monitor base class
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

This is associates both QMP and HMP monitors with a character
device backend.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 chardev/char.c             |  3 ++-
 gdbstub/system.c           |  4 ++--
 include/monitor/monitor.h  |  4 ++--
 monitor/hmp.c              | 10 ++++++--
 monitor/monitor-internal.h |  2 ++
 monitor/monitor.c          | 47 ++++++++++++++++++++++++++++++--------
 monitor/qmp.c              | 18 ++++++++++-----
 stubs/monitor-internal.c   |  2 +-
 8 files changed, 67 insertions(+), 23 deletions(-)

diff --git a/chardev/char.c b/chardev/char.c
index 813c04d953..981fbb1aaa 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -804,8 +804,9 @@ static Chardev *qemu_chr_new_from_name(const char *label, const char *filename,
     }
 
     if (qemu_opt_get_bool(opts, "mux", 0)) {
+        const char *chardev_id = qemu_opts_id(opts);
         assert(permit_mux_mon);
-        monitor_new_hmp(chr, true, &err);
+        monitor_new_hmp(chardev_id, true, &err);
         if (err) {
             error_report_err(err);
             object_unparent(OBJECT(chr));
diff --git a/gdbstub/system.c b/gdbstub/system.c
index 18f6a62b2e..80175e7fa2 100644
--- a/gdbstub/system.c
+++ b/gdbstub/system.c
@@ -387,9 +387,9 @@ bool gdbserver_start(const char *device, Error **errp)
         qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
 
         /* Initialize a monitor terminal for gdb */
-        mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB,
+        mon_chr = qemu_chardev_new("gdbchrdev0", TYPE_CHARDEV_GDB,
                                    NULL, NULL, &error_abort);
-        monitor_new_hmp(mon_chr, false, &error_abort);
+        monitor_new_hmp("gdbchrdev0", false, &error_abort);
     } else {
         qemu_chr_fe_deinit(&gdbserver_system_state.chr, true);
         mon_chr = gdbserver_system_state.mon_chr;
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 2e9f9e12e9..a135b3a590 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -28,8 +28,8 @@ bool monitor_cur_is_qmp(void);
 
 void monitor_init_globals(void);
 void monitor_init_globals_core(void);
-void monitor_new_qmp(Chardev *chr, bool pretty, Error **errp);
-void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp);
+void monitor_new_qmp(const char *chardev_id, bool pretty, Error **errp);
+void monitor_new_hmp(const char *chardev_id, bool use_readline, Error **errp);
 int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp);
 int monitor_new_opts(QemuOpts *opts, Error **errp);
 void monitor_cleanup(void);
diff --git a/monitor/hmp.c b/monitor/hmp.c
index 81047d2513..4ab81b5904 100644
--- a/monitor/hmp.c
+++ b/monitor/hmp.c
@@ -23,6 +23,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qapi/error.h"
 #include <dirent.h>
 #include "hw/core/qdev.h"
 #include "hw/core/sysemu-cpu-ops.h"
@@ -1538,8 +1539,9 @@ static void monitor_readline_flush(void *opaque)
     monitor_flush(&mon->parent_obj);
 }
 
-void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp)
+void monitor_new_hmp(const char *chardev_id, bool use_readline, Error **errp)
 {
+    ERRP_GUARD();
     MonitorHMP *mon;
     static int counter;
     g_autofree char *id = g_strdup_printf("hmpcompat%d", counter++);
@@ -1547,13 +1549,17 @@ void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp)
                                         object_get_objects_root(),
                                         id,
                                         errp,
+                                        "chardev", chardev_id,
                                         NULL);
+
     if (!obj) {
         return;
     }
+
     mon = MONITOR_HMP(obj);
 
-    if (!qemu_chr_fe_init(&mon->parent_obj.chr, chr, errp)) {
+    monitor_complete(MONITOR(mon), errp);
+    if (*errp) {
         object_unparent(OBJECT(mon));
         return;
     }
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 05c1f2f5e0..145d52fd71 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -108,6 +108,7 @@ struct MonitorClass {
 
 struct Monitor {
     Object parent;
+    char *chardev_id;
     CharFrontend chr;
     int suspend_cnt;            /* Needs to be accessed atomically */
     bool is_qmp;
@@ -192,6 +193,7 @@ extern QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
 extern QemuMutex monitor_lock;
 extern MonitorList mon_list;
 
+void monitor_complete(Monitor *mon, Error **errp);
 void monitor_data_init(Monitor *mon, bool is_qmp, bool skip_flush,
                        bool use_io_thread);
 void monitor_data_destroy(Monitor *mon);
diff --git a/monitor/monitor.c b/monitor/monitor.c
index a497c25c54..747ca27fd5 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -77,10 +77,31 @@ OBJECT_DEFINE_TYPE(Monitor, monitor, MONITOR, OBJECT);
 
 static void monitor_finalize(Object *obj)
 {
+    Monitor *mon = MONITOR(obj);
+
+    g_free(mon->chardev_id);
+}
+
+static char *monitor_get_chardev_id(Object *obj, Error **errp)
+{
+    Monitor *mon = MONITOR(obj);
+
+    return g_strdup(mon->chardev_id);
+}
+
+static void monitor_set_chardev_id(Object *obj, const char *str, Error **errp)
+{
+    Monitor *mon = MONITOR(obj);
+
+    g_free(mon->chardev_id);
+    mon->chardev_id = g_strdup(str);
 }
 
 static void monitor_class_init(ObjectClass *cls, const void *data)
 {
+    object_class_property_add_str(cls, "chardev",
+                                  monitor_get_chardev_id,
+                                  monitor_set_chardev_id);
 }
 
 static void monitor_init(Object *obj)
@@ -729,16 +750,24 @@ void monitor_init_globals(void)
     aio_co_schedule(iohandler_get_aio_context(), qmp_dispatcher_co);
 }
 
-int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
+void monitor_complete(Monitor *mon, Error **errp)
 {
-    ERRP_GUARD();
-    Chardev *chr;
+    if (mon->chardev_id) {
+        Chardev *chr = qemu_chr_find(mon->chardev_id);
+        if (chr == NULL) {
+            error_setg(errp, "chardev \"%s\" not found", mon->chardev_id);
+            return;
+        }
 
-    chr = qemu_chr_find(opts->chardev);
-    if (chr == NULL) {
-        error_setg(errp, "chardev \"%s\" not found", opts->chardev);
-        return -1;
+        if (!qemu_chr_fe_init(&mon->chr, chr, errp)) {
+            return;
+        }
     }
+}
+
+int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
+{
+    ERRP_GUARD();
 
     if (!opts->has_mode) {
         opts->mode = allow_hmp ? MONITOR_MODE_READLINE : MONITOR_MODE_CONTROL;
@@ -746,7 +775,7 @@ int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
 
     switch (opts->mode) {
     case MONITOR_MODE_CONTROL:
-        monitor_new_qmp(chr, opts->pretty, errp);
+        monitor_new_qmp(opts->chardev, opts->pretty, errp);
         break;
     case MONITOR_MODE_READLINE:
         if (!allow_hmp) {
@@ -757,7 +786,7 @@ int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
             error_setg(errp, "'pretty' is not compatible with HMP monitors");
             return -1;
         }
-        monitor_new_hmp(chr, true, errp);
+        monitor_new_hmp(opts->chardev, true, errp);
         break;
     default:
         g_assert_not_reached();
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 5231ed506a..0abf2677f9 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -527,8 +527,9 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
     monitor_list_append(&mon->parent_obj);
 }
 
-void monitor_new_qmp(Chardev *chr, bool pretty, Error **errp)
+void monitor_new_qmp(const char *chardev_id, bool pretty, Error **errp)
 {
+    ERRP_GUARD();
     MonitorQMP *mon;
     static int counter;
     g_autofree char *id = g_strdup_printf("qmpcompat%d", counter++);
@@ -536,21 +537,26 @@ void monitor_new_qmp(Chardev *chr, bool pretty, Error **errp)
                                         object_get_objects_root(),
                                         id,
                                         errp,
+                                        "chardev", chardev_id,
                                         NULL);
+
     if (!obj) {
         return;
     }
-    mon = MONITOR_QMP(obj);
 
-    if (!qemu_chr_fe_init(&mon->parent_obj.chr, chr, errp)) {
+    mon = MONITOR_QMP(obj);
+    monitor_complete(MONITOR(mon), errp);
+    if (*errp) {
         object_unparent(OBJECT(mon));
         return;
     }
+
     qemu_chr_fe_set_echo(&mon->parent_obj.chr, true);
 
     /* Note: we run QMP monitor in I/O thread when @chr supports that */
     monitor_data_init(&mon->parent_obj, true, false,
-                      qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT));
+                      qemu_chr_has_feature(mon->parent_obj.chr.chr,
+                                           QEMU_CHAR_FEATURE_GCONTEXT));
 
     mon->pretty = pretty;
 
@@ -563,12 +569,12 @@ void monitor_new_qmp(Chardev *chr, bool pretty, Error **errp)
          * Make sure the old iowatch is gone.  It's possible when
          * e.g. the chardev is in client mode, with wait=on.
          */
-        remove_fd_in_watch(chr);
+        remove_fd_in_watch(mon->parent_obj.chr.chr);
         /*
          * Clean up listener IO sources early to prevent racy fd
          * handling between the main thread and the I/O thread.
          */
-        remove_listener_fd_in_watch(chr);
+        remove_listener_fd_in_watch(mon->parent_obj.chr.chr);
         /*
          * We can't call qemu_chr_fe_set_handlers() directly here
          * since chardev might be running in the monitor I/O
diff --git a/stubs/monitor-internal.c b/stubs/monitor-internal.c
index 23d58da184..51db7588b9 100644
--- a/stubs/monitor-internal.c
+++ b/stubs/monitor-internal.c
@@ -8,6 +8,6 @@ int monitor_get_fd(Monitor *mon, const char *name, Error **errp)
     return -1;
 }
 
-void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp)
+void monitor_new_hmp(const char *chardev_id, bool use_readline, Error **errp)
 {
 }
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 08/35] monitor: add 'pretty' property to QMP Monitor class
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

This determines whether the QMP JSON responses are pretty printed
with newlines and indentation, or compact with no extra whitespace.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/qmp.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/monitor/qmp.c b/monitor/qmp.c
index 0abf2677f9..2a8532ef96 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -77,8 +77,25 @@ static void monitor_qmp_finalize(Object *obj)
 {
 }
 
+static bool monitor_qmp_get_pretty(Object *obj, Error **errp)
+{
+    MonitorQMP *mon = MONITOR_QMP(obj);
+
+    return mon->pretty;
+}
+
+static void monitor_qmp_set_pretty(Object *obj, bool val, Error **errp)
+{
+    MonitorQMP *mon = MONITOR_QMP(obj);
+
+    mon->pretty = val;
+}
+
 static void monitor_qmp_class_init(ObjectClass *cls, const void *data)
 {
+    object_class_property_add_bool(cls, "pretty",
+                                   monitor_qmp_get_pretty,
+                                   monitor_qmp_set_pretty);
 }
 
 static void monitor_qmp_init(Object *obj)
@@ -538,6 +555,7 @@ void monitor_new_qmp(const char *chardev_id, bool pretty, Error **errp)
                                         id,
                                         errp,
                                         "chardev", chardev_id,
+                                        "pretty", pretty ? "yes" : "no",
                                         NULL);
 
     if (!obj) {
@@ -558,8 +576,6 @@ void monitor_new_qmp(const char *chardev_id, bool pretty, Error **errp)
                       qemu_chr_has_feature(mon->parent_obj.chr.chr,
                                            QEMU_CHAR_FEATURE_GCONTEXT));
 
-    mon->pretty = pretty;
-
     qemu_mutex_init(&mon->qmp_queue_lock);
     mon->qmp_requests = g_queue_new();
 
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 07/35] monitor: add 'readline' property to HMP Monitor class
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

This determines whether a human monitor runs with readline for
interactive use, or without readline for non-interactive use by
the GDB stub.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/hmp.c | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/monitor/hmp.c b/monitor/hmp.c
index 4ab81b5904..d5905e2279 100644
--- a/monitor/hmp.c
+++ b/monitor/hmp.c
@@ -50,12 +50,37 @@ static void monitor_hmp_finalize(Object *obj)
 {
 }
 
+static bool monitor_hmp_get_readline(Object *obj, Error **errp)
+{
+    MonitorHMP *mon = MONITOR_HMP(obj);
+
+    return mon->use_readline;
+}
+
+static void monitor_hmp_set_readline(Object *obj, bool val, Error **errp)
+{
+    MonitorHMP *mon = MONITOR_HMP(obj);
+
+    mon->use_readline = val;
+}
+
 static void monitor_hmp_class_init(ObjectClass *cls, const void *data)
 {
+    object_class_property_add_bool(cls, "readline",
+                                   monitor_hmp_get_readline,
+                                   monitor_hmp_set_readline);
 }
 
 static void monitor_hmp_init(Object *obj)
 {
+    MonitorHMP *hmp = MONITOR_HMP(obj);
+
+    /*
+     * Default to common case for external HMP use,
+     * as opposed to non-interactive internal use
+     * from gdbstub
+     */
+    hmp->use_readline = true;
 }
 
 static void monitor_command_cb(void *opaque, const char *cmdline,
@@ -1550,6 +1575,7 @@ void monitor_new_hmp(const char *chardev_id, bool use_readline, Error **errp)
                                         id,
                                         errp,
                                         "chardev", chardev_id,
+                                        "readline", use_readline ? "yes" : "no",
                                         NULL);
 
     if (!obj) {
@@ -1566,7 +1592,6 @@ void monitor_new_hmp(const char *chardev_id, bool use_readline, Error **errp)
 
     monitor_data_init(&mon->parent_obj, false, false, false);
 
-    mon->use_readline = use_readline;
     if (mon->use_readline) {
         mon->rs = readline_init(monitor_readline_printf,
                                 monitor_readline_flush,
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 13/35] monitor: use class methods for monitor_accept_input
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

This removes the need for using monitor_is_qmp() to check the
subclass type, which is an anti-pattern.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/hmp.c              | 16 ++++++++++++++++
 monitor/monitor-internal.h |  5 +++++
 monitor/monitor.c          | 12 +++---------
 3 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/monitor/hmp.c b/monitor/hmp.c
index 08055839a4..1da9370ead 100644
--- a/monitor/hmp.c
+++ b/monitor/hmp.c
@@ -70,6 +70,7 @@ static void monitor_hmp_set_readline(Object *obj, bool val, Error **errp)
 
 int monitor_hmp_vprintf(Monitor *mon, const char *fmt, va_list ap)
     G_GNUC_PRINTF(2, 0);
+static void monitor_hmp_accept_input(Monitor *mon);
 
 static void monitor_hmp_class_init(ObjectClass *cls, const void *data)
 {
@@ -80,6 +81,7 @@ static void monitor_hmp_class_init(ObjectClass *cls, const void *data)
                                    monitor_hmp_set_readline);
 
     moncls->vprintf = monitor_hmp_vprintf;
+    moncls->accept_input = monitor_hmp_accept_input;
 }
 
 static void monitor_hmp_init(Object *obj)
@@ -100,6 +102,20 @@ int monitor_hmp_vprintf(Monitor *mon, const char *fmt, va_list ap)
     return monitor_puts(mon, buf);
 }
 
+static void monitor_hmp_accept_input(Monitor *mon)
+{
+    qemu_mutex_lock(&mon->mon_lock);
+    if (mon->reset_seen) {
+        MonitorHMP *hmp = MONITOR_HMP(mon);
+        assert(hmp->rs);
+        readline_restart(hmp->rs);
+        qemu_mutex_unlock(&mon->mon_lock);
+        readline_show_prompt(hmp->rs);
+    } else {
+        qemu_mutex_unlock(&mon->mon_lock);
+    }
+}
+
 static void monitor_command_cb(void *opaque, const char *cmdline,
                                void *readline_opaque)
 {
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 763b5c9625..592f146331 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -116,6 +116,11 @@ struct MonitorClass {
      * notifications back to the client
      */
     void (*emit_event)(Monitor *mon, QAPIEvent event, QDict *qdict);
+    /*
+     * If non-NULL, perform any actions needed to prepare
+     * the monitor to accept further client input
+     */
+    void (*accept_input)(Monitor *mon);
 };
 
 struct Monitor {
diff --git a/monitor/monitor.c b/monitor/monitor.c
index 6f0353d9f1..2f16cd3053 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -576,16 +576,10 @@ int monitor_suspend(Monitor *mon)
 static void monitor_accept_input(void *opaque)
 {
     Monitor *mon = opaque;
+    MonitorClass *cls = MONITOR_GET_CLASS(mon);
 
-    qemu_mutex_lock(&mon->mon_lock);
-    if (!monitor_is_qmp(mon) && mon->reset_seen) {
-        MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, parent_obj);
-        assert(hmp_mon->rs);
-        readline_restart(hmp_mon->rs);
-        qemu_mutex_unlock(&mon->mon_lock);
-        readline_show_prompt(hmp_mon->rs);
-    } else {
-        qemu_mutex_unlock(&mon->mon_lock);
+    if (cls->accept_input) {
+        cls->accept_input(mon);
     }
 
     qemu_chr_fe_accept_input(&mon->chr);
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 09/35] monitor: remove 'skip_flush' field
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

The 'skip_flush' field is set on the dummy throwaway HMP monitor
object created by QMP's  'human-monitor-command', as an indication
not to try to write data to the chardev. Instead the QMP command
impl will grab the data straight out of the in-memory buffer.

The flag is redundant, however, as the monitor code could instead
simply check the 'fe_is_open' field on the CharFrontend, which
will be false in the same scenarios that 'skip_flush' is true.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/hmp.c              |  2 +-
 monitor/monitor-internal.h |  4 +---
 monitor/monitor.c          | 11 +++++++----
 monitor/qmp-cmds.c         |  2 +-
 monitor/qmp.c              |  2 +-
 5 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/monitor/hmp.c b/monitor/hmp.c
index d5905e2279..516aa25d4c 100644
--- a/monitor/hmp.c
+++ b/monitor/hmp.c
@@ -1590,7 +1590,7 @@ void monitor_new_hmp(const char *chardev_id, bool use_readline, Error **errp)
         return;
     }
 
-    monitor_data_init(&mon->parent_obj, false, false, false);
+    monitor_data_init(&mon->parent_obj, false, false);
 
     if (mon->use_readline) {
         mon->rs = readline_init(monitor_readline_printf,
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 145d52fd71..d34f9be139 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -112,7 +112,6 @@ struct Monitor {
     CharFrontend chr;
     int suspend_cnt;            /* Needs to be accessed atomically */
     bool is_qmp;
-    bool skip_flush;
     bool use_io_thread;
 
     char *mon_cpu_path;
@@ -194,8 +193,7 @@ extern QemuMutex monitor_lock;
 extern MonitorList mon_list;
 
 void monitor_complete(Monitor *mon, Error **errp);
-void monitor_data_init(Monitor *mon, bool is_qmp, bool skip_flush,
-                       bool use_io_thread);
+void monitor_data_init(Monitor *mon, bool is_qmp, bool use_io_thread);
 void monitor_data_destroy(Monitor *mon);
 int monitor_can_read(void *opaque);
 void monitor_list_append(Monitor *mon);
diff --git a/monitor/monitor.c b/monitor/monitor.c
index 747ca27fd5..e3e5623a4b 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -188,7 +188,12 @@ void monitor_flush_locked(Monitor *mon)
     size_t len;
     const char *buf;
 
-    if (mon->skip_flush) {
+    /*
+     * When used by QMP human-monitor-command, no chardev
+     * will be connected, as we want to just collect the
+     * output in the buffer
+     */
+    if (!mon->chr.fe_is_open) {
         return;
     }
 
@@ -642,8 +647,7 @@ static void monitor_iothread_init(void)
     mon_iothread = iothread_create("mon_iothread", &error_abort);
 }
 
-void monitor_data_init(Monitor *mon, bool is_qmp, bool skip_flush,
-                       bool use_io_thread)
+void monitor_data_init(Monitor *mon, bool is_qmp, bool use_io_thread)
 {
     if (use_io_thread && !mon_iothread) {
         monitor_iothread_init();
@@ -651,7 +655,6 @@ void monitor_data_init(Monitor *mon, bool is_qmp, bool skip_flush,
     qemu_mutex_init(&mon->mon_lock);
     mon->is_qmp = is_qmp;
     mon->outbuf = g_string_new(NULL);
-    mon->skip_flush = skip_flush;
     mon->use_io_thread = use_io_thread;
 }
 
diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c
index bfde769ef0..0d9adad288 100644
--- a/monitor/qmp-cmds.c
+++ b/monitor/qmp-cmds.c
@@ -168,7 +168,7 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
     char *output = NULL;
     MonitorHMP *hmp = MONITOR_HMP(object_new(TYPE_MONITOR_HMP));
 
-    monitor_data_init(&hmp->parent_obj, false, true, false);
+    monitor_data_init(&hmp->parent_obj, false, false);
 
     if (has_cpu_index) {
         int ret = monitor_set_cpu(&hmp->parent_obj, cpu_index);
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 2a8532ef96..e3318b57db 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -572,7 +572,7 @@ void monitor_new_qmp(const char *chardev_id, bool pretty, Error **errp)
     qemu_chr_fe_set_echo(&mon->parent_obj.chr, true);
 
     /* Note: we run QMP monitor in I/O thread when @chr supports that */
-    monitor_data_init(&mon->parent_obj, true, false,
+    monitor_data_init(&mon->parent_obj, true,
                       qemu_chr_has_feature(mon->parent_obj.chr.chr,
                                            QEMU_CHAR_FEATURE_GCONTEXT));
 
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 10/35] monitor: move monitor_data_(init|destroy) into QOM init/finalize
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

Start to take advantage of QOM, by using object init and finalize
methods to replace monitor_data_init and monitor_data_destroy.

A standalone helper is provided to enable the I/O thread for QMP
where appropriate for the chardev backend.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/hmp.c              |  6 +++--
 monitor/monitor-internal.h |  3 +--
 monitor/monitor.c          | 46 +++++++++++++-------------------------
 monitor/qmp-cmds.c         |  3 ---
 monitor/qmp.c              | 34 +++++++++++++++-------------
 5 files changed, 40 insertions(+), 52 deletions(-)

diff --git a/monitor/hmp.c b/monitor/hmp.c
index 516aa25d4c..2bb2333da5 100644
--- a/monitor/hmp.c
+++ b/monitor/hmp.c
@@ -48,6 +48,10 @@ OBJECT_DEFINE_TYPE(MonitorHMP, monitor_hmp, MONITOR_HMP, MONITOR);
 
 static void monitor_hmp_finalize(Object *obj)
 {
+    MonitorHMP *mon = MONITOR_HMP(obj);
+    if (mon->rs) {
+        readline_free(mon->rs);
+    }
 }
 
 static bool monitor_hmp_get_readline(Object *obj, Error **errp)
@@ -1590,8 +1594,6 @@ void monitor_new_hmp(const char *chardev_id, bool use_readline, Error **errp)
         return;
     }
 
-    monitor_data_init(&mon->parent_obj, false, false);
-
     if (mon->use_readline) {
         mon->rs = readline_init(monitor_readline_printf,
                                 monitor_readline_flush,
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index d34f9be139..6a4c3b0f37 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -193,8 +193,7 @@ extern QemuMutex monitor_lock;
 extern MonitorList mon_list;
 
 void monitor_complete(Monitor *mon, Error **errp);
-void monitor_data_init(Monitor *mon, bool is_qmp, bool use_io_thread);
-void monitor_data_destroy(Monitor *mon);
+void monitor_iothread_init(Monitor *mon);
 int monitor_can_read(void *opaque);
 void monitor_list_append(Monitor *mon);
 void monitor_fdsets_cleanup(void);
diff --git a/monitor/monitor.c b/monitor/monitor.c
index e3e5623a4b..76df379a2c 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -80,6 +80,10 @@ static void monitor_finalize(Object *obj)
     Monitor *mon = MONITOR(obj);
 
     g_free(mon->chardev_id);
+    g_free(mon->mon_cpu_path);
+    qemu_chr_fe_deinit(&mon->chr, false);
+    g_string_free(mon->outbuf, true);
+    qemu_mutex_destroy(&mon->mon_lock);
 }
 
 static char *monitor_get_chardev_id(Object *obj, Error **errp)
@@ -106,6 +110,11 @@ static void monitor_class_init(ObjectClass *cls, const void *data)
 
 static void monitor_init(Object *obj)
 {
+    Monitor *mon = MONITOR(obj);
+
+    qemu_mutex_init(&mon->mon_lock);
+    mon->is_qmp = !!object_dynamic_cast(obj, TYPE_MONITOR_QMP);
+    mon->outbuf = g_string_new(NULL);
 }
 
 Monitor *monitor_cur(void)
@@ -637,38 +646,16 @@ void monitor_list_append(Monitor *mon)
     qemu_mutex_unlock(&monitor_lock);
 
     if (mon) {
-        monitor_data_destroy(mon);
         object_unparent(OBJECT(mon));
     }
 }
 
-static void monitor_iothread_init(void)
-{
-    mon_iothread = iothread_create("mon_iothread", &error_abort);
-}
-
-void monitor_data_init(Monitor *mon, bool is_qmp, bool use_io_thread)
+void monitor_iothread_init(Monitor *mon)
 {
-    if (use_io_thread && !mon_iothread) {
-        monitor_iothread_init();
+    if (!mon_iothread) {
+        mon_iothread = iothread_create("mon_iothread", &error_abort);
     }
-    qemu_mutex_init(&mon->mon_lock);
-    mon->is_qmp = is_qmp;
-    mon->outbuf = g_string_new(NULL);
-    mon->use_io_thread = use_io_thread;
-}
-
-void monitor_data_destroy(Monitor *mon)
-{
-    g_free(mon->mon_cpu_path);
-    qemu_chr_fe_deinit(&mon->chr, false);
-    if (monitor_is_qmp(mon)) {
-        monitor_data_destroy_qmp(container_of(mon, MonitorQMP, parent_obj));
-    } else {
-        readline_free(container_of(mon, MonitorHMP, parent_obj)->rs);
-    }
-    g_string_free(mon->outbuf, true);
-    qemu_mutex_destroy(&mon->mon_lock);
+    mon->use_io_thread = true;
 }
 
 void monitor_cleanup(void)
@@ -686,7 +673,7 @@ void monitor_cleanup(void)
      * Letting the iothread continue while shutting down the dispatcher
      * means that new requests may still be coming in. This is okay,
      * we'll just leave them in the queue without sending a response
-     * and monitor_data_destroy() will free them.
+     * and object finalization will free them.
      */
     WITH_QEMU_LOCK_GUARD(&monitor_lock) {
         qmp_dispatcher_co_shutdown = true;
@@ -700,8 +687,8 @@ void monitor_cleanup(void)
     /*
      * We need to explicitly stop the I/O thread (but not destroy it),
      * clean up the monitor resources, then destroy the I/O thread since
-     * we need to unregister from chardev below in
-     * monitor_data_destroy(), and chardev is not thread-safe yet
+     * we need to unregister from chardev below in object
+     * finalization, and chardev is not thread-safe yet
      */
     if (mon_iothread) {
         iothread_stop(mon_iothread);
@@ -716,7 +703,6 @@ void monitor_cleanup(void)
         /* Permit QAPI event emission from character frontend release */
         qemu_mutex_unlock(&monitor_lock);
         monitor_flush(mon);
-        monitor_data_destroy(mon);
         qemu_mutex_lock(&monitor_lock);
         object_unparent(OBJECT(mon));
     }
diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c
index 0d9adad288..6cb0b587fb 100644
--- a/monitor/qmp-cmds.c
+++ b/monitor/qmp-cmds.c
@@ -168,8 +168,6 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
     char *output = NULL;
     MonitorHMP *hmp = MONITOR_HMP(object_new(TYPE_MONITOR_HMP));
 
-    monitor_data_init(&hmp->parent_obj, false, false);
-
     if (has_cpu_index) {
         int ret = monitor_set_cpu(&hmp->parent_obj, cpu_index);
         if (ret < 0) {
@@ -186,7 +184,6 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
     }
 
 out:
-    monitor_data_destroy(&hmp->parent_obj);
     object_unref(hmp);
     return output;
 }
diff --git a/monitor/qmp.c b/monitor/qmp.c
index e3318b57db..694d303215 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -73,8 +73,16 @@ QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
 
 OBJECT_DEFINE_TYPE(MonitorQMP, monitor_qmp, MONITOR_QMP, MONITOR);
 
+static void monitor_qmp_cleanup_req_queue_locked(MonitorQMP *mon);
+
 static void monitor_qmp_finalize(Object *obj)
 {
+    MonitorQMP *mon = MONITOR_QMP(obj);
+
+    json_message_parser_destroy(&mon->parser);
+    qemu_mutex_destroy(&mon->qmp_queue_lock);
+    monitor_qmp_cleanup_req_queue_locked(mon);
+    g_queue_free(mon->qmp_requests);
 }
 
 static bool monitor_qmp_get_pretty(Object *obj, Error **errp)
@@ -98,8 +106,15 @@ static void monitor_qmp_class_init(ObjectClass *cls, const void *data)
                                    monitor_qmp_set_pretty);
 }
 
+static void handle_qmp_command(void *opaque, QObject *req, Error *err);
 static void monitor_qmp_init(Object *obj)
 {
+    MonitorQMP *mon = MONITOR_QMP(obj);
+
+    qemu_mutex_init(&mon->qmp_queue_lock);
+    mon->qmp_requests = g_queue_new();
+
+    json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL);
 }
 
 static bool qmp_oob_enabled(MonitorQMP *mon)
@@ -522,14 +537,6 @@ static void monitor_qmp_event(void *opaque, QEMUChrEvent event)
     }
 }
 
-void monitor_data_destroy_qmp(MonitorQMP *mon)
-{
-    json_message_parser_destroy(&mon->parser);
-    qemu_mutex_destroy(&mon->qmp_queue_lock);
-    monitor_qmp_cleanup_req_queue_locked(mon);
-    g_queue_free(mon->qmp_requests);
-}
-
 static void monitor_qmp_setup_handlers_bh(void *opaque)
 {
     MonitorQMP *mon = opaque;
@@ -572,14 +579,11 @@ void monitor_new_qmp(const char *chardev_id, bool pretty, Error **errp)
     qemu_chr_fe_set_echo(&mon->parent_obj.chr, true);
 
     /* Note: we run QMP monitor in I/O thread when @chr supports that */
-    monitor_data_init(&mon->parent_obj, true,
-                      qemu_chr_has_feature(mon->parent_obj.chr.chr,
-                                           QEMU_CHAR_FEATURE_GCONTEXT));
-
-    qemu_mutex_init(&mon->qmp_queue_lock);
-    mon->qmp_requests = g_queue_new();
+    if (qemu_chr_has_feature(mon->parent_obj.chr.chr,
+                             QEMU_CHAR_FEATURE_GCONTEXT)) {
+        monitor_iothread_init(&mon->parent_obj);
+    }
 
-    json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL);
     if (mon->parent_obj.use_io_thread) {
         /*
          * Make sure the old iowatch is gone.  It's possible when
-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH v3 3/3] KVM: arm64: top up stage 2 memcache for dirty logging faults
From: Bradley Morgan @ 2026-06-24 17:39 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton
  Cc: Fuad Tabba, Joey Gouly, Steffen Eiden, Suzuki K Poulose,
	Zenghui Yu, Catalin Marinas, Will Deacon, Quentin Perret,
	Vincent Donnefort, Gavin Shan, Alexandru Elisei, linux-arm-kernel,
	kvmarm, linux-kernel, stable
In-Reply-To: <20260624160028.15591-4-include@grrlz.net>

On June 24, 2026 5:00:28 PM GMT+01:00, Bradley Morgan <include@grrlz.net>
wrote:
>Dirty logging forces new stage 2 mappings down to page size, but
>it does not always remove an existing block mapping before the next
>fault. Eager splitting is best effort and is disabled by default.
>
>A permission fault on such a block can still need a page table page
>to install the smaller mapping. Top up the memcache for any permission
>fault while dirty logging is active, not only for write faults.
>
>The issue was discovered [1] by Sashiko.
>
>Link: https://lore.kernel.org/all/59984F6D-06F2-4302-BDD7-92DF334E8FA0@grrlz.net/T/#t [1]
>
>Fixes: 6f745f1bb5bf ("KVM: arm64: Convert user_mem_abort() to generic page-table API")
>Cc: stable@vger.kernel.org
>Signed-off-by: Bradley Morgan <include@grrlz.net>
>---
> arch/arm64/kvm/mmu.c | 9 ++++-----
> 1 file changed, 4 insertions(+), 5 deletions(-)
>
>diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
>index 3f57f6825a33..8911e319e6fa 100644
>--- a/arch/arm64/kvm/mmu.c
>+++ b/arch/arm64/kvm/mmu.c
>@@ -2122,13 +2122,12 @@ static int user_mem_abort(const struct kvm_s2_fault_desc *s2fd)
> 	 * Permission faults just need to update the existing leaf entry,
> 	 * and so normally don't require allocations from the memcache. The
> 	 * only exception to this is when dirty logging is enabled at runtime
>-	 * and a write fault needs to collapse a block entry into a table. With
>-	 * pKVM, they may still need a fresh mapping object if the fault turns
>-	 * page entries into a block entry.
>+	 * and a fault needs to collapse a block entry into a table. With pKVM,
>+	 * they may still need a fresh mapping object if the fault turns page
>+	 * entries into a block entry.
> 	 */
> 	memcache = get_mmu_memcache(s2fd->vcpu);
>-	if (!perm_fault || (memslot_is_logging(s2fd->memslot) &&
>-			    kvm_is_write_fault(s2fd->vcpu))) {
>+	if (!perm_fault || memslot_is_logging(s2fd->memslot)) {
> 		ret = topup_mmu_memcache(s2fd->vcpu, memcache);
> 		if (ret)
> 			return ret;
>

Note: Patch 3 seems to conflict because of patch 2 (the comments)


Oops! :(

V4 (after people have their review go), will contain one commit (patch
3) with the updated comments.

Patch 1 and 2 applies as usual.

Apologies for my messup. 

Thanks!


^ permalink raw reply

* [PATCH v5 15/35] monitor: use dynamic cast in monitor_qmp_requests_pop_any_with_lock
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

This eliminates a use of monitor_is_qmp() from the QMP coroutine
dispatch path.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/qmp.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/monitor/qmp.c b/monitor/qmp.c
index 93f576c19d..d2a03bb7e3 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -277,11 +277,12 @@ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
     MonitorQMP *qmp_mon;
 
     QTAILQ_FOREACH(mon, &mon_list, entry) {
-        if (!monitor_is_qmp(mon)) {
+        qmp_mon = MONITOR_QMP(
+            object_dynamic_cast(OBJECT(mon), TYPE_MONITOR_QMP));
+        if (!qmp_mon) {
             continue;
         }
 
-        qmp_mon = container_of(mon, MonitorQMP, parent_obj);
         qemu_mutex_lock(&qmp_mon->qmp_queue_lock);
         req_obj = g_queue_pop_head(qmp_mon->qmp_requests);
         if (req_obj) {
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 12/35] monitor: use class methods for monitor_qapi_event_emit
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

This removes the need for using monitor_is_qmp() to check the
subclass type, which is an anti-pattern.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 include/monitor/monitor.h  |  1 +
 monitor/monitor-internal.h |  5 +++++
 monitor/monitor.c          | 15 +++------------
 monitor/qmp.c              | 20 ++++++++++++++++++++
 4 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index a135b3a590..8cb3db677b 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -3,6 +3,7 @@
 
 #include "block/block.h"
 #include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-emit-events.h"
 #include "qemu/readline.h"
 #include "exec/hwaddr.h"
 #include "qom/object.h"
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 23cef68153..763b5c9625 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -111,6 +111,11 @@ struct MonitorClass {
      */
     int (*vprintf)(Monitor *mon, const char *fmt, va_list ap)
         G_GNUC_PRINTF(2, 0);
+    /*
+     * If non-NULL, the monitor is able to send event
+     * notifications back to the client
+     */
+    void (*emit_event)(Monitor *mon, QAPIEvent event, QDict *qdict);
 };
 
 struct Monitor {
diff --git a/monitor/monitor.c b/monitor/monitor.c
index 8b70380d64..6f0353d9f1 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -346,22 +346,13 @@ static inline QEMUClockType monitor_get_event_clock(void)
 static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict)
 {
     Monitor *mon;
-    MonitorQMP *qmp_mon;
 
     trace_monitor_protocol_event_emit(event, qdict);
     QTAILQ_FOREACH(mon, &mon_list, entry) {
-        if (!monitor_is_qmp(mon)) {
-            continue;
+        MonitorClass *cls = MONITOR_GET_CLASS(mon);
+        if (cls->emit_event) {
+            cls->emit_event(mon, event, qdict);
         }
-
-        qmp_mon = container_of(mon, MonitorQMP, parent_obj);
-        {
-            QEMU_LOCK_GUARD(&mon->mon_lock);
-            if (qmp_mon->commands == &qmp_cap_negotiation_commands) {
-                continue;
-            }
-        }
-        qmp_send_response(qmp_mon, qdict);
     }
 }
 
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 694d303215..ec17050a70 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -99,11 +99,17 @@ static void monitor_qmp_set_pretty(Object *obj, bool val, Error **errp)
     mon->pretty = val;
 }
 
+static void monitor_qmp_emit_event(Monitor *mon, QAPIEvent event, QDict *qdict);
+
 static void monitor_qmp_class_init(ObjectClass *cls, const void *data)
 {
+    MonitorClass *moncls = MONITOR_CLASS(cls);
+
     object_class_property_add_bool(cls, "pretty",
                                    monitor_qmp_get_pretty,
                                    monitor_qmp_set_pretty);
+
+    moncls->emit_event = monitor_qmp_emit_event;
 }
 
 static void handle_qmp_command(void *opaque, QObject *req, Error *err);
@@ -117,6 +123,20 @@ static void monitor_qmp_init(Object *obj)
     json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL);
 }
 
+static void monitor_qmp_emit_event(Monitor *mon, QAPIEvent event, QDict *qdict)
+{
+    MonitorQMP *qmp = MONITOR_QMP(mon);
+
+    WITH_QEMU_LOCK_GUARD(&mon->mon_lock) {
+        if (qmp->commands == &qmp_cap_negotiation_commands) {
+            return;
+        }
+    }
+
+    qmp_send_response(qmp, qdict);
+}
+
+
 static bool qmp_oob_enabled(MonitorQMP *mon)
 {
     return mon->capab[QMP_CAPABILITY_OOB];
-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH v1] drm/bridge: analogix_dp: Apply standard DP training delay helpers
From: Vicente Bergas @ 2026-06-24 17:39 UTC (permalink / raw)
  To: Damon Ding
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
	Dmitry Baryshkov, Heiko Stuebner, Marek Szyprowski, dri-devel,
	linux-kernel
In-Reply-To: <20260623075207.320603-1-damon.ding@rock-chips.com>

On Tue, Jun 23, 2026 at 9:52 AM Damon Ding <damon.ding@rock-chips.com> wrote:
>
> Replace hardcoded fixed usleep_range() delays during clock recovery and
> channel equalization with drm_dp_link_train_clock_recovery_delay()
> and drm_dp_link_train_channel_eq_delay() helpers.
>
> The original fixed delays are only valid for the case where bit[6:0] of
> DPCD TRAINING_AUX_RD_INTERVAL(0000Eh) is 0x00, while core helpers apply
> spec-compliant timings matching actual receiver capability values.
>
> Additionally, add dpcd buffer to struct analogix_dp_device to cache
> receiver capabilities. Call drm_dp_read_dpcd_caps() at commit entry to
> populate cached DPCD data for subsequent link training steps, and
> prepare for further usage of other DP helper APIs.
>
> Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
> ---
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 10 ++++++++--
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  2 ++
>  2 files changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 1d39a354c3d9..30c0c0b41d5a 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -330,7 +330,7 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp)
>         u8 voltage_swing, pre_emphasis, training_lane;
>         u8 link_status[DP_LINK_STATUS_SIZE];
>
> -       usleep_range(100, 101);
> +       drm_dp_link_train_clock_recovery_delay(&dp->aux, dp->dpcd);
>
>         lane_count = dp->link_train.lane_count;
>
> @@ -393,7 +393,7 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
>         u32 reg;
>         u8 link_status[DP_LINK_STATUS_SIZE];
>
> -       usleep_range(400, 401);
> +       drm_dp_link_train_channel_eq_delay(&dp->aux, dp->dpcd);
>
>         lane_count = dp->link_train.lane_count;
>
> @@ -754,6 +754,12 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
>  {
>         int ret;
>
> +       ret = drm_dp_read_dpcd_caps(&dp->aux, dp->dpcd);
> +       if (ret < 0) {
> +               dev_err(dp->dev, "failed to read dpcd caps: %d\n", ret);
> +               return ret;
> +       }
> +
>         ret = analogix_dp_train_link(dp);
>         if (ret) {
>                 dev_err(dp->dev, "unable to do link train, ret=%d\n", ret);
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
> index 94348c4e3623..c7997677a286 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
> @@ -169,6 +169,8 @@ struct analogix_dp_device {
>         bool                    fast_train_enable;
>         bool                    psr_supported;
>
> +       u8 dpcd[DP_RECEIVER_CAP_SIZE];
> +
>         struct analogix_dp_plat_data *plat_data;
>  };
>
> --
> 2.34.1

Tested-by: Vicente Bergas

This patch was tested toghether with
[PATCH v2] drm/bridge: analogix_dp: Fix PE/VS value shift mismatch
during link training

Regards,
  Vicente.

^ permalink raw reply

* [PATCH v5 03/35] monitor: replace 'common' with 'parent_obj' in MonitorQMP
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

The field name 'parent_obj' is standard practice for QOM structs
so align the QMP monitor.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/monitor-internal.h |  2 +-
 monitor/monitor.c          |  4 ++--
 monitor/qmp-cmds-control.c |  4 ++--
 monitor/qmp.c              | 40 +++++++++++++++++++-------------------
 4 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index eb301ea796..4da2b2a677 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -141,7 +141,7 @@ struct MonitorHMP {
 };
 
 typedef struct {
-    Monitor common;
+    Monitor parent_obj;
     JSONMessageParser parser;
     bool pretty;
     /*
diff --git a/monitor/monitor.c b/monitor/monitor.c
index 2a1b511ff4..0b7b464ebe 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -308,7 +308,7 @@ static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict)
             continue;
         }
 
-        qmp_mon = container_of(mon, MonitorQMP, common);
+        qmp_mon = container_of(mon, MonitorQMP, parent_obj);
         {
             QEMU_LOCK_GUARD(&mon->mon_lock);
             if (qmp_mon->commands == &qmp_cap_negotiation_commands) {
@@ -625,7 +625,7 @@ void monitor_data_destroy(Monitor *mon)
     g_free(mon->mon_cpu_path);
     qemu_chr_fe_deinit(&mon->chr, false);
     if (monitor_is_qmp(mon)) {
-        monitor_data_destroy_qmp(container_of(mon, MonitorQMP, common));
+        monitor_data_destroy_qmp(container_of(mon, MonitorQMP, parent_obj));
     } else {
         readline_free(container_of(mon, MonitorHMP, parent_obj)->rs);
     }
diff --git a/monitor/qmp-cmds-control.c b/monitor/qmp-cmds-control.c
index 150ca9f5cb..af6a2a118b 100644
--- a/monitor/qmp-cmds-control.c
+++ b/monitor/qmp-cmds-control.c
@@ -76,7 +76,7 @@ void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable,
     MonitorQMP *mon;
 
     assert(monitor_is_qmp(cur_mon));
-    mon = container_of(cur_mon, MonitorQMP, common);
+    mon = container_of(cur_mon, MonitorQMP, parent_obj);
 
     if (mon->commands == &qmp_commands) {
         error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
@@ -126,7 +126,7 @@ CommandInfoList *qmp_query_commands(Error **errp)
     MonitorQMP *mon;
 
     assert(monitor_is_qmp(cur_mon));
-    mon = container_of(cur_mon, MonitorQMP, common);
+    mon = container_of(cur_mon, MonitorQMP, parent_obj);
 
     qmp_for_each_command(mon->commands, query_commands_cb, &list);
 
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 687019811f..27934206db 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -80,7 +80,7 @@ static void monitor_qmp_caps_reset(MonitorQMP *mon)
 {
     memset(mon->capab_offered, 0, sizeof(mon->capab_offered));
     memset(mon->capab, 0, sizeof(mon->capab));
-    mon->capab_offered[QMP_CAPABILITY_OOB] = mon->common.use_io_thread;
+    mon->capab_offered[QMP_CAPABILITY_OOB] = mon->parent_obj.use_io_thread;
 }
 
 static void qmp_request_free(QMPRequest *req)
@@ -124,7 +124,7 @@ static void monitor_qmp_cleanup_queue_and_resume(MonitorQMP *mon)
          * when we get here while the monitor is suspended.  An
          * unfortunately timed CHR_EVENT_CLOSED can do the trick.
          */
-        monitor_resume(&mon->common);
+        monitor_resume(&mon->parent_obj);
     }
 
 }
@@ -139,7 +139,7 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp)
     trace_monitor_qmp_respond(mon, json->str);
 
     g_string_append_c(json, '\n');
-    monitor_puts(&mon->common, json->str);
+    monitor_puts(&mon->parent_obj, json->str);
 
     g_string_free(json, true);
 }
@@ -166,7 +166,7 @@ static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req)
     QDict *error;
 
     rsp = qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon),
-                       &mon->common);
+                       &mon->parent_obj);
 
     if (mon->commands == &qmp_cap_negotiation_commands) {
         error = qdict_get_qdict(rsp, "error");
@@ -207,7 +207,7 @@ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
             continue;
         }
 
-        qmp_mon = container_of(mon, MonitorQMP, common);
+        qmp_mon = container_of(mon, MonitorQMP, parent_obj);
         qemu_mutex_lock(&qmp_mon->qmp_queue_lock);
         req_obj = g_queue_pop_head(qmp_mon->qmp_requests);
         if (req_obj) {
@@ -302,7 +302,7 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
         oob_enabled = qmp_oob_enabled(mon);
         if (oob_enabled
             && mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
-            monitor_resume(&mon->common);
+            monitor_resume(&mon->parent_obj);
         }
 
         /*
@@ -343,7 +343,7 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
         }
 
         if (!oob_enabled) {
-            monitor_resume(&mon->common);
+            monitor_resume(&mon->parent_obj);
         }
 
         qmp_request_free(req_obj);
@@ -408,7 +408,7 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err)
          */
         if (!qmp_oob_enabled(mon) ||
             mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
-            monitor_suspend(&mon->common);
+            monitor_suspend(&mon->parent_obj);
         }
 
         /*
@@ -462,7 +462,7 @@ static void monitor_qmp_event(void *opaque, QEMUChrEvent event)
 
     switch (event) {
     case CHR_EVENT_OPENED:
-        WITH_QEMU_LOCK_GUARD(&mon->common.mon_lock) {
+        WITH_QEMU_LOCK_GUARD(&mon->parent_obj.mon_lock) {
             mon->commands = &qmp_cap_negotiation_commands;
             monitor_qmp_caps_reset(mon);
         }
@@ -504,27 +504,27 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
     MonitorQMP *mon = opaque;
     GMainContext *context;
 
-    assert(mon->common.use_io_thread);
+    assert(mon->parent_obj.use_io_thread);
     context = iothread_get_g_main_context(mon_iothread);
     assert(context);
-    qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read,
+    qemu_chr_fe_set_handlers(&mon->parent_obj.chr, monitor_can_read,
                              monitor_qmp_read, monitor_qmp_event,
-                             NULL, &mon->common, context, true);
-    monitor_list_append(&mon->common);
+                             NULL, &mon->parent_obj, context, true);
+    monitor_list_append(&mon->parent_obj);
 }
 
 void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp)
 {
     MonitorQMP *mon = g_new0(MonitorQMP, 1);
 
-    if (!qemu_chr_fe_init(&mon->common.chr, chr, errp)) {
+    if (!qemu_chr_fe_init(&mon->parent_obj.chr, chr, errp)) {
         g_free(mon);
         return;
     }
-    qemu_chr_fe_set_echo(&mon->common.chr, true);
+    qemu_chr_fe_set_echo(&mon->parent_obj.chr, true);
 
     /* Note: we run QMP monitor in I/O thread when @chr supports that */
-    monitor_data_init(&mon->common, true, false,
+    monitor_data_init(&mon->parent_obj, true, false,
                       qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT));
 
     mon->pretty = pretty;
@@ -533,7 +533,7 @@ void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp)
     mon->qmp_requests = g_queue_new();
 
     json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL);
-    if (mon->common.use_io_thread) {
+    if (mon->parent_obj.use_io_thread) {
         /*
          * Make sure the old iowatch is gone.  It's possible when
          * e.g. the chardev is in client mode, with wait=on.
@@ -553,9 +553,9 @@ void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp)
                                 monitor_qmp_setup_handlers_bh, mon);
         /* The bottom half will add @mon to @mon_list */
     } else {
-        qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read,
+        qemu_chr_fe_set_handlers(&mon->parent_obj.chr, monitor_can_read,
                                  monitor_qmp_read, monitor_qmp_event,
-                                 NULL, &mon->common, NULL, true);
-        monitor_list_append(&mon->common);
+                                 NULL, &mon->parent_obj, NULL, true);
+        monitor_list_append(&mon->parent_obj);
     }
 }
-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH RFC] bpf: add DAG fast-path in verifier to skip redundant state pruning
From: L0 @ 2026-06-24 17:38 UTC (permalink / raw)
  To: ast; +Cc: daniel, eddyz87, paul.chaignon, bpf
In-Reply-To: <DIVM9YXYJV5N.2TEM951JWKD95@gmail.com>

Alexei,

I know you're deep in the review backlog and the prototype share is still
pending. Rather than waiting, I'm sending this ahead -- apologies for
jumping the queue.

You said the DAG specialization isn't interesting (fair -- loops are
everywhere now), but that do_check_insn() as a transfer function in the
dataflow analysis is viable, and that merge_verifier_state() is the key.
I agree it's the key, and it's where I started -- one level down. A join is
only as sound as the domain it operates on, so before the join itself I
pinned down that domain: the scalar state merge_verifier_state() combines,
tnum x cnum, as it stands in bpf-next (a975094bf).

I built a small, self-contained Rust model of it -- the tnum bit domain
(tnum.c), the cnum circular-number range domain (cnum.c / cnum_defs.h), and
the reduced-product reduction in reg_bounds_sync(). Three results, all
machine-checked (10 harnesses, Kani 0.67.0 / CBMC):

1. Soundness. Each harness states the abstraction is sound -- for every
concrete x in gamma(a) and y in gamma(b), f(x,y) lies in gamma(f#(a,b))
-- and Kani discharges it over the full bit-vector input space (not
sampled). Covered: tnum add/sub/and/or/xor, tnum_in, the cnum subset
order, and cnum64_cnum32_intersect.

2. Faithfulness. The differential test links the *unmodified* kernel
tnum.c + cnum.c against userspace stub headers (the .c is byte-for-byte
bpf-next, no kernel build needed) and fuzzes them against the Rust model,
N=2000 x 11 ops, 0 mismatch. So (1) carries over to the C, not just the
model.

3. A question this raised (for Eduard/Paul as much as anyone). On the model
Kani proves the cross-width reduction idempotent -- one __reg_deduce_bounds()
pass reaches the fixpoint over all inputs -- which surprised me, since
9e5fcb003aec ("bpf: Avoid one round of bounds deduction") established two
rounds as the minimum, with verifier_bounds/"cross sign boundary, negative
overlap" failing at one.

But that analysis predates the circular-number refactor (256f0071f9b6),
which collapsed the four deduce sub-steps into two. So the honest question:
did cnum make the second __reg_deduce_bounds() in reg_bounds_sync()
(verifier.c:2082) redundant, or does the cross-sign case still rely on it
and my isolated model simply misses that state? I haven't built the tree to
run that selftest at one call yet -- curious whether the round count was
revisited after cnum landed.

Scope, honestly: this is only the scalar tnum/cnum transfer and reduction
math, not the whole verifier, and I'm not claiming any over-conservative
(false-reject) bug -- none turned up here. The security boundary
(regsafe/stacksafe) stays in the kernel; this is a verification model, the
PCC split we talked about -- a checker that produces a proof, not a
replacement for the kernel's check.

Everything is in one ~600-line crate and reproduces from scratch with a
single script -- ./reproduce.sh runs the 11 unit tests, the differential,
and all 10 Kani proofs:

https://github.com/hyeon3125-dev/bpf-verifier-rs (against bpf-next a975094bf)

so you can re-run the soundness checks and the diff against C directly,
rather than taking my word for any of it.

And when you share the transfer + join prototype, the part I'd most like to
compare is exactly the representation it uses for the abstract state, and
how merge_verifier_state() joins it.

- Seunghyeon


On Sat, May 30, 2026 at 10:23 AM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Fri May 29, 2026 at 1:38 AM PDT, Seunghyeon Lee wrote:
> > bpf: add DAG fast-path in verifier to skip redundant state pruning
> >
> > The BPF verifier's state-equivalence loop (is_state_visited /
> > states_equal) dominates load time for programs with acyclic control
> > flow graphs (DAGs). In a DAG, every instruction is reached via exactly
> > one path: no state is ever revisited, making state-pruning comparisons
> > mathematically vacuous.
> >
> > This RFC proposes three components:
> >
> > 1. compute_dag_topo() -- replaces a simple is_acyclic_dag() bool.
> >    Uses Kahn's algorithm (O(V+E), O(V) space, no recursion) to detect
> >    back-edges AND preserve the topological visit order for use in (2).
> >    Handles BPF_JMP32, BPF_LD_IMM64 wide instructions, and falls back
> >    conservatively on BPF-to-BPF subprogram calls.
> >
> > 2. do_check_dag() -- fast-path verifier for confirmed-DAG programs.
> >    Critical correctness property: maintains a per-instruction state
> >    table (states[insn_cnt]) and, at every join point (in_degree > 1),
> >    calls merge_verifier_state() to conservatively merge all incoming
> >    paths BEFORE processing the instruction. This ensures the verifier
> >    never sees a register as initialized when any predecessor path left
> >    it NOT_INIT.
> >
> >    Skips is_state_visited() / states_equal() entirely; provably safe
> >    because topological order guarantees each instruction is processed
> >    exactly once.
> >
> > 3. Full fallback: if compute_dag_topo() returns NULL (cyclic program,
> >    subprog, or allocation failure), or if do_check_dag() returns an
> >    error, the unmodified do_check() runs unchanged.
> >
> > Register-state correctness at join points
> > -----------------------------------------
> > When paths A and B converge at instruction N, the verifier must hold
> > the least precise state that is safe for both paths.
> >
> >   Path A arrives at insn N: R2 = scalar [0, 5]
> >   Path B arrives at insn N: R2 = NOT_INIT
> >   merge_verifier_state() result: R2 = NOT_INIT
> >   -> verifier correctly rejects any use of R2 at N
> >
> > Without this merge (a flaw in naive linear-scan approaches), the
> > verifier would see only the state from whichever path was processed
> > last in memory order, potentially accepting a program that
> > dereferences an uninitialized register at runtime.
> >
> > RFC design question:
> > --------------------
> > do_check_dag()'s inner per-instruction verification step requires
> > calling into do_check()'s inner loop logic, which is not currently
> > factored as a callable sub-function. We propose two integration
> > options and request maintainer guidance:
> >
> >   Option A: Extract a verify_one_insn() helper from do_check()'s
> >             inner loop; do_check_dag() calls it per topological step.
>
> Specializing the verifier for DAG only case is not interesting.
> Almost all programs now contain loops.
> But the approach to use do_check_insn() as a transfer function
> in the data flow analysis is totally viable.
> I've been prototyping such transfer + join verifier for some time.
> Will share soon. What merge_verifier_state() does is a key.

^ permalink raw reply

* [PATCH v5 11/35] monitor: use class methods for monitor_vprintf
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

This removes the need for using monitor_is_qmp() to check the
subclass type, which is an anti-pattern.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dave@treblig.org>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/hmp.c              | 13 +++++++++++++
 monitor/monitor-internal.h |  7 +++++++
 monitor/monitor.c          | 11 ++++-------
 3 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/monitor/hmp.c b/monitor/hmp.c
index 2bb2333da5..08055839a4 100644
--- a/monitor/hmp.c
+++ b/monitor/hmp.c
@@ -68,11 +68,18 @@ static void monitor_hmp_set_readline(Object *obj, bool val, Error **errp)
     mon->use_readline = val;
 }
 
+int monitor_hmp_vprintf(Monitor *mon, const char *fmt, va_list ap)
+    G_GNUC_PRINTF(2, 0);
+
 static void monitor_hmp_class_init(ObjectClass *cls, const void *data)
 {
+    MonitorClass *moncls = MONITOR_CLASS(cls);
+
     object_class_property_add_bool(cls, "readline",
                                    monitor_hmp_get_readline,
                                    monitor_hmp_set_readline);
+
+    moncls->vprintf = monitor_hmp_vprintf;
 }
 
 static void monitor_hmp_init(Object *obj)
@@ -87,6 +94,12 @@ static void monitor_hmp_init(Object *obj)
     hmp->use_readline = true;
 }
 
+int monitor_hmp_vprintf(Monitor *mon, const char *fmt, va_list ap)
+{
+    g_autofree char *buf = g_strdup_vprintf(fmt, ap);
+    return monitor_puts(mon, buf);
+}
+
 static void monitor_command_cb(void *opaque, const char *cmdline,
                                void *readline_opaque)
 {
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 6a4c3b0f37..23cef68153 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -104,6 +104,13 @@ typedef struct HMPCommand {
 
 struct MonitorClass {
     ObjectClass parent_class;
+
+    /*
+     * If non-NULL, the monitor is able to print messages
+     * for attention of the client user
+     */
+    int (*vprintf)(Monitor *mon, const char *fmt, va_list ap)
+        G_GNUC_PRINTF(2, 0);
 };
 
 struct Monitor {
diff --git a/monitor/monitor.c b/monitor/monitor.c
index 76df379a2c..8b70380d64 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -262,21 +262,18 @@ int monitor_puts(Monitor *mon, const char *str)
 
 int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
 {
-    char *buf;
-    int n;
+    MonitorClass *moncls;
 
     if (!mon) {
         return -1;
     }
 
-    if (monitor_is_qmp(mon)) {
+    moncls = MONITOR_GET_CLASS(mon);
+    if (!moncls->vprintf) {
         return -1;
     }
 
-    buf = g_strdup_vprintf(fmt, ap);
-    n = monitor_puts(mon, buf);
-    g_free(buf);
-    return n;
+    return moncls->vprintf(mon, fmt, ap);
 }
 
 int monitor_printf(Monitor *mon, const char *fmt, ...)
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 04/35] monitor: rename monitor_init* to monitor_new*
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

The current "monitor_init" functions will clash with the methods of the
same name that are required by QOM. To ease the transition to QOM,
rename them out of the way.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dave@treblig.org>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 chardev/char.c                       |  2 +-
 gdbstub/system.c                     |  2 +-
 include/monitor/monitor.h            |  8 ++++----
 monitor/hmp.c                        |  2 +-
 monitor/monitor.c                    | 10 +++++-----
 monitor/qmp.c                        |  2 +-
 storage-daemon/qemu-storage-daemon.c |  2 +-
 stubs/monitor-internal.c             |  2 +-
 system/vl.c                          |  2 +-
 9 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/chardev/char.c b/chardev/char.c
index ca8b37ed8d..813c04d953 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -805,7 +805,7 @@ static Chardev *qemu_chr_new_from_name(const char *label, const char *filename,
 
     if (qemu_opt_get_bool(opts, "mux", 0)) {
         assert(permit_mux_mon);
-        monitor_init_hmp(chr, true, &err);
+        monitor_new_hmp(chr, true, &err);
         if (err) {
             error_report_err(err);
             object_unparent(OBJECT(chr));
diff --git a/gdbstub/system.c b/gdbstub/system.c
index 2063b63b2f..18f6a62b2e 100644
--- a/gdbstub/system.c
+++ b/gdbstub/system.c
@@ -389,7 +389,7 @@ bool gdbserver_start(const char *device, Error **errp)
         /* Initialize a monitor terminal for gdb */
         mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB,
                                    NULL, NULL, &error_abort);
-        monitor_init_hmp(mon_chr, false, &error_abort);
+        monitor_new_hmp(mon_chr, false, &error_abort);
     } else {
         qemu_chr_fe_deinit(&gdbserver_system_state.chr, true);
         mon_chr = gdbserver_system_state.mon_chr;
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 55649a8664..b9642b58ba 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -19,10 +19,10 @@ bool monitor_cur_is_qmp(void);
 
 void monitor_init_globals(void);
 void monitor_init_globals_core(void);
-void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp);
-void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp);
-int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp);
-int monitor_init_opts(QemuOpts *opts, Error **errp);
+void monitor_new_qmp(Chardev *chr, bool pretty, Error **errp);
+void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp);
+int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp);
+int monitor_new_opts(QemuOpts *opts, Error **errp);
 void monitor_cleanup(void);
 
 int monitor_suspend(Monitor *mon);
diff --git a/monitor/hmp.c b/monitor/hmp.c
index 3dde52ddbe..4e4468424a 100644
--- a/monitor/hmp.c
+++ b/monitor/hmp.c
@@ -1524,7 +1524,7 @@ static void monitor_readline_flush(void *opaque)
     monitor_flush(&mon->parent_obj);
 }
 
-void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp)
+void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp)
 {
     MonitorHMP *mon = g_new0(MonitorHMP, 1);
 
diff --git a/monitor/monitor.c b/monitor/monitor.c
index 0b7b464ebe..a87597e606 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -715,7 +715,7 @@ void monitor_init_globals(void)
     aio_co_schedule(iohandler_get_aio_context(), qmp_dispatcher_co);
 }
 
-int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp)
+int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
 {
     ERRP_GUARD();
     Chardev *chr;
@@ -732,7 +732,7 @@ int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp)
 
     switch (opts->mode) {
     case MONITOR_MODE_CONTROL:
-        monitor_init_qmp(chr, opts->pretty, errp);
+        monitor_new_qmp(chr, opts->pretty, errp);
         break;
     case MONITOR_MODE_READLINE:
         if (!allow_hmp) {
@@ -743,7 +743,7 @@ int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp)
             error_setg(errp, "'pretty' is not compatible with HMP monitors");
             return -1;
         }
-        monitor_init_hmp(chr, true, errp);
+        monitor_new_hmp(chr, true, errp);
         break;
     default:
         g_assert_not_reached();
@@ -752,7 +752,7 @@ int monitor_init(MonitorOptions *opts, bool allow_hmp, Error **errp)
     return *errp ? -1 : 0;
 }
 
-int monitor_init_opts(QemuOpts *opts, Error **errp)
+int monitor_new_opts(QemuOpts *opts, Error **errp)
 {
     Visitor *v;
     MonitorOptions *options;
@@ -765,7 +765,7 @@ int monitor_init_opts(QemuOpts *opts, Error **errp)
         return -1;
     }
 
-    ret = monitor_init(options, true, errp);
+    ret = monitor_new(options, true, errp);
     qapi_free_MonitorOptions(options);
     return ret;
 }
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 27934206db..cb28a95efd 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -513,7 +513,7 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
     monitor_list_append(&mon->parent_obj);
 }
 
-void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp)
+void monitor_new_qmp(Chardev *chr, bool pretty, Error **errp)
 {
     MonitorQMP *mon = g_new0(MonitorQMP, 1);
 
diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c
index eb72561358..50dbfbd97a 100644
--- a/storage-daemon/qemu-storage-daemon.c
+++ b/storage-daemon/qemu-storage-daemon.c
@@ -330,7 +330,7 @@ static void process_options(int argc, char *argv[], bool pre_init_pass)
                 visit_free(v);
 
                 /* TODO Catch duplicate monitor IDs */
-                monitor_init(monitor, false, &error_fatal);
+                monitor_new(monitor, false, &error_fatal);
                 qapi_free_MonitorOptions(monitor);
                 break;
             }
diff --git a/stubs/monitor-internal.c b/stubs/monitor-internal.c
index 4fece49d53..23d58da184 100644
--- a/stubs/monitor-internal.c
+++ b/stubs/monitor-internal.c
@@ -8,6 +8,6 @@ int monitor_get_fd(Monitor *mon, const char *name, Error **errp)
     return -1;
 }
 
-void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp)
+void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp)
 {
 }
diff --git a/system/vl.c b/system/vl.c
index 1c0da7df29..fb36140aac 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -1247,7 +1247,7 @@ static int fsdev_init_func(void *opaque, QemuOpts *opts, Error **errp)
 
 static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp)
 {
-    return monitor_init_opts(opts, errp);
+    return monitor_new_opts(opts, errp);
 }
 
 static void monitor_parse(const char *str, const char *mode, bool pretty)
-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH v1 05/13] iio: dac: max5522: Simplify device abstraction
From: Jonathan Cameron @ 2026-06-24 17:38 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: David Lechner, Nuno Sá, Andy Shevchenko, Antoniu Miclaus,
	linux-iio, linux-kernel
In-Reply-To: <54b79462e753b99c132a835f6b618b3cef76fa9c.1781883685.git.u.kleine-koenig@baylibre.com>

On Fri, 19 Jun 2026 17:54:33 +0200
Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com> wrote:

> The driver only supports a single chip variant since it's birth in 2022.
> Both the spi id_table and the of id_table are essentially unused (only
> assigned to a write-only member in private data).
> 
> Hardcode the device name and then drop various unused stuff from the
> driver. While touching the spi id_table assign .name using a named
> initializer.
> 
> Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
Hmm. This one was a bit silly wasn't it? :)

Applied.

> ---
>  drivers/iio/dac/max5522.c | 31 +++----------------------------
>  1 file changed, 3 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c
> index b52a9cc1da79..cfbe3a6e0449 100644
> --- a/drivers/iio/dac/max5522.c
> +++ b/drivers/iio/dac/max5522.c
> @@ -25,15 +25,8 @@
>  
>  #define MAX5522_REG_DATA(x)	((x) + MAX5522_CTRL_LOAD_IN_A)
>  
> -struct max5522_chip_info {
> -	const char *name;
> -	const struct iio_chan_spec *channels;
> -	unsigned int num_channels;
> -};
> -
>  struct max5522_state {
>  	struct regmap *regmap;
> -	const struct max5522_chip_info *chip_info;
>  	unsigned short dac_cache[2];
>  	int vref_mV;
>  };
> @@ -58,18 +51,6 @@ static const struct iio_chan_spec max5522_channels[] = {
>  	MAX5522_CHANNEL(1),
>  };
>  
> -enum max5522_type {
> -	ID_MAX5522,
> -};
> -
> -static const struct max5522_chip_info max5522_chip_info_tbl[] = {
> -	[ID_MAX5522] = {
> -		.name = "max5522",
> -		.channels = max5522_channels,
> -		.num_channels = 2,
> -	},
> -};
> -
>  static inline int max5522_info_to_reg(struct iio_chan_spec const *chan)
>  {
>  	return MAX5522_REG_DATA(chan->channel);
> @@ -140,9 +121,6 @@ static int max5522_spi_probe(struct spi_device *spi)
>  	}
>  
>  	state = iio_priv(indio_dev);
> -	state->chip_info = spi_get_device_match_data(spi);
> -	if (!state->chip_info)
> -		return -EINVAL;
>  
>  	ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vrefin");
>  	if (ret < 0)
> @@ -159,22 +137,19 @@ static int max5522_spi_probe(struct spi_device *spi)
>  	indio_dev->modes = INDIO_DIRECT_MODE;
>  	indio_dev->channels = max5522_channels;
>  	indio_dev->num_channels = ARRAY_SIZE(max5522_channels);
> -	indio_dev->name = max5522_chip_info_tbl[ID_MAX5522].name;
> +	indio_dev->name = "max5522";
>  
>  	return devm_iio_device_register(&spi->dev, indio_dev);
>  }
>  
>  static const struct spi_device_id max5522_ids[] = {
> -	{ "max5522", (kernel_ulong_t)&max5522_chip_info_tbl[ID_MAX5522] },
> +	{ .name = "max5522" },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(spi, max5522_ids);
>  
>  static const struct of_device_id max5522_of_match[] = {
> -	{
> -		.compatible = "maxim,max5522",
> -		.data = &max5522_chip_info_tbl[ID_MAX5522],
> -	},
> +	{ .compatible = "maxim,max5522" },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(of, max5522_of_match);


^ permalink raw reply

* [PATCH v5 01/35] qom: replace 'can_be_deleted' with 'prepare_delete'
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

While most objects can perform all their cleanup in the finalizer
method, there can be interactions with other resources / subsystems
/ threads which require that some cleanup be performed on an user
creatable object before unparenting it and entering finalization.

The current 'can_be_deleted' method runs in the deletion path and
is intended to be used to block deletion. While it could be used
to perform cleanup tasks, its name suggests it should be free of
side-effects.

Generalize this by renaming it to 'prepare_delete', explicitly
allowing for cleanup to be provided. Existing users of 'can_be_deleted'
are re-written, which provides them with more detailed/tailored error
messages.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 backends/cryptodev.c             | 10 +++++++---
 backends/hostmem.c               |  5 +++--
 backends/iommufd.c               | 10 +++++++---
 block/throttle-groups.c          | 10 +++++++---
 event-loop-base.c                |  8 ++++----
 include/qom/object_interfaces.h  | 26 +++++++++++++++++---------
 include/system/event-loop-base.h |  2 +-
 net/can/can_core.c               |  5 +++--
 qom/object_interfaces.c          | 14 ++++++--------
 tests/qemu-iotests/245           |  4 ++--
 util/main-loop.c                 |  5 +++--
 11 files changed, 60 insertions(+), 39 deletions(-)

diff --git a/backends/cryptodev.c b/backends/cryptodev.c
index 79f8882d3b..90110dc633 100644
--- a/backends/cryptodev.c
+++ b/backends/cryptodev.c
@@ -454,9 +454,13 @@ bool cryptodev_backend_is_ready(CryptoDevBackend *backend)
 }
 
 static bool
-cryptodev_backend_can_be_deleted(UserCreatable *uc)
+cryptodev_backend_prepare_delete(UserCreatable *uc, Error **errp)
 {
-    return !cryptodev_backend_is_used(CRYPTODEV_BACKEND(uc));
+    if (cryptodev_backend_is_used(CRYPTODEV_BACKEND(uc))) {
+        error_setg(errp, "Cryptodev backend is still in use");
+        return false;
+    }
+    return true;
 }
 
 static void cryptodev_backend_instance_init(Object *obj)
@@ -613,7 +617,7 @@ cryptodev_backend_class_init(ObjectClass *oc, const void *data)
     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 
     ucc->complete = cryptodev_backend_complete;
-    ucc->can_be_deleted = cryptodev_backend_can_be_deleted;
+    ucc->prepare_delete = cryptodev_backend_prepare_delete;
 
     QTAILQ_INIT(&crypto_clients);
     object_class_property_add(oc, "queues", "uint32",
diff --git a/backends/hostmem.c b/backends/hostmem.c
index cd2085fb3c..eb915c64bc 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -434,9 +434,10 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
 }
 
 static bool
-host_memory_backend_can_be_deleted(UserCreatable *uc)
+host_memory_backend_prepare_delete(UserCreatable *uc, Error **errp)
 {
     if (host_memory_backend_is_mapped(MEMORY_BACKEND(uc))) {
+        error_setg(errp, "Host memory backend is still mapped");
         return false;
     } else {
         return true;
@@ -508,7 +509,7 @@ host_memory_backend_class_init(ObjectClass *oc, const void *data)
     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 
     ucc->complete = host_memory_backend_memory_complete;
-    ucc->can_be_deleted = host_memory_backend_can_be_deleted;
+    ucc->prepare_delete = host_memory_backend_prepare_delete;
 
     object_class_property_add_bool(oc, "merge",
         host_memory_backend_get_merge,
diff --git a/backends/iommufd.c b/backends/iommufd.c
index 09624cd652..7af49f6de3 100644
--- a/backends/iommufd.c
+++ b/backends/iommufd.c
@@ -63,11 +63,15 @@ static void iommufd_backend_set_fd(Object *obj, const char *str, Error **errp)
     trace_iommu_backend_set_fd(be->fd);
 }
 
-static bool iommufd_backend_can_be_deleted(UserCreatable *uc)
+static bool iommufd_backend_prepare_delete(UserCreatable *uc, Error **errp)
 {
     IOMMUFDBackend *be = IOMMUFD_BACKEND(uc);
 
-    return !be->users;
+    if (be->users) {
+        error_setg(errp, "IOMMUFD backend still has %d users", be->users);
+        return false;
+    }
+    return true;
 }
 
 static void iommufd_backend_complete(UserCreatable *uc, Error **errp)
@@ -92,7 +96,7 @@ static void iommufd_backend_class_init(ObjectClass *oc, const void *data)
 {
     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 
-    ucc->can_be_deleted = iommufd_backend_can_be_deleted;
+    ucc->prepare_delete = iommufd_backend_prepare_delete;
     ucc->complete = iommufd_backend_complete;
 
     object_class_property_add_str(oc, "fd", NULL, iommufd_backend_set_fd);
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 4b1b1944c2..7836fc4c76 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -960,9 +960,13 @@ static void throttle_group_get_limits(Object *obj, Visitor *v,
     visit_type_ThrottleLimits(v, name, &argp, errp);
 }
 
-static bool throttle_group_can_be_deleted(UserCreatable *uc)
+static bool throttle_group_prepare_delete(UserCreatable *uc, Error **errp)
 {
-    return OBJECT(uc)->ref == 1;
+    if (OBJECT(uc)->ref > 1) {
+        error_setg(errp, "Throttle group still has multiple references");
+        return false;
+    }
+    return true;
 }
 
 static void throttle_group_obj_class_init(ObjectClass *klass,
@@ -972,7 +976,7 @@ static void throttle_group_obj_class_init(ObjectClass *klass,
     UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
 
     ucc->complete = throttle_group_obj_complete;
-    ucc->can_be_deleted = throttle_group_can_be_deleted;
+    ucc->prepare_delete = throttle_group_prepare_delete;
 
     /* individual properties */
     for (i = 0; i < sizeof(properties) / sizeof(ThrottleParamInfo); i++) {
diff --git a/event-loop-base.c b/event-loop-base.c
index 8ca143bea4..ee5987ddbf 100644
--- a/event-loop-base.c
+++ b/event-loop-base.c
@@ -85,13 +85,13 @@ static void event_loop_base_complete(UserCreatable *uc, Error **errp)
     }
 }
 
-static bool event_loop_base_can_be_deleted(UserCreatable *uc)
+static bool event_loop_base_prepare_delete(UserCreatable *uc, Error **errp)
 {
     EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
     EventLoopBase *backend = EVENT_LOOP_BASE(uc);
 
-    if (bc->can_be_deleted) {
-        return bc->can_be_deleted(backend);
+    if (bc->prepare_delete) {
+        return bc->prepare_delete(backend, errp);
     }
 
     return true;
@@ -102,7 +102,7 @@ static void event_loop_base_class_init(ObjectClass *klass,
 {
     UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
     ucc->complete = event_loop_base_complete;
-    ucc->can_be_deleted = event_loop_base_can_be_deleted;
+    ucc->prepare_delete = event_loop_base_prepare_delete;
 
     object_class_property_add(klass, "aio-max-batch", "int",
                               event_loop_base_get_param,
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
index e2b8615617..afd0fb93b2 100644
--- a/include/qom/object_interfaces.h
+++ b/include/qom/object_interfaces.h
@@ -20,8 +20,10 @@ typedef struct UserCreatable UserCreatable;
  * UserCreatableClass:
  * @parent_class: the base class
  * @complete: callback to be called after @obj's properties are set.
- * @can_be_deleted: callback to be called before an object is removed
- * to check if @obj can be removed safely.
+ * @prepare_delete: to be called before an attempt to delete @obj
+ * to validate whether the object can be deleted and trigger any
+ * cleanup of any resources which have to be dealt with before the
+ * object is unparented and enters finalization.
  *
  * Interface is designed to work with -object/object-add/object_add
  * commands.
@@ -36,7 +38,9 @@ typedef struct UserCreatable UserCreatable;
  * For objects created without using -object/object-add/object_add,
  * @user_creatable_complete() wrapper should be called manually if
  * object's type implements USER_CREATABLE interface and needs
- * complete() callback to be called.
+ * complete() callback to be called. Similarly @user_creatable_prepare_delete()
+ * should be called manually prior to an attempt to the delete the
+ * object.
  */
 struct UserCreatableClass {
     /* <private> */
@@ -44,7 +48,7 @@ struct UserCreatableClass {
 
     /* <public> */
     void (*complete)(UserCreatable *uc, Error **errp);
-    bool (*can_be_deleted)(UserCreatable *uc);
+    bool (*prepare_delete)(UserCreatable *uc, Error **errp);
 };
 
 /**
@@ -61,13 +65,17 @@ struct UserCreatableClass {
 bool user_creatable_complete(UserCreatable *uc, Error **errp);
 
 /**
- * user_creatable_can_be_deleted:
- * @uc: the object whose can_be_deleted() method is called if implemented
+ * user_creatable_prepare_delete:
+ * @uc: the user-creatable object whose prepare_delete() method is called
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * Wrapper to call prepare_delete() class method if defined, otherwise
+ * does nothing.
  *
- * Wrapper to call can_be_deleted() method if one of types it's inherited
- * from implements USER_CREATABLE interface.
+ * Returns: %true on success or if prepare_delete() is not defined,
+ *          %false on failure.
  */
-bool user_creatable_can_be_deleted(UserCreatable *uc);
+bool user_creatable_prepare_delete(UserCreatable *uc, Error **errp);
 
 /**
  * user_creatable_add_qapi:
diff --git a/include/system/event-loop-base.h b/include/system/event-loop-base.h
index 130629e7f3..1e1e427ac7 100644
--- a/include/system/event-loop-base.h
+++ b/include/system/event-loop-base.h
@@ -24,7 +24,7 @@ struct EventLoopBaseClass {
 
     void (*init)(EventLoopBase *base, Error **errp);
     void (*update_params)(EventLoopBase *base, Error **errp);
-    bool (*can_be_deleted)(EventLoopBase *base);
+    bool (*prepare_delete)(EventLoopBase *base, Error **errp);
 };
 
 struct EventLoopBase {
diff --git a/net/can/can_core.c b/net/can/can_core.c
index 77fe2b8ba4..8df9375167 100644
--- a/net/can/can_core.c
+++ b/net/can/can_core.c
@@ -143,8 +143,9 @@ int can_bus_client_set_filters(CanBusClientState *client,
 }
 
 
-static bool can_bus_can_be_deleted(UserCreatable *uc)
+static bool can_bus_prepare_delete(UserCreatable *uc, Error **errp)
 {
+    error_setg(errp, "Deleting can bus devices is not supported");
     return false;
 }
 
@@ -153,7 +154,7 @@ static void can_bus_class_init(ObjectClass *klass,
 {
     UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass);
 
-    uc_klass->can_be_deleted = can_bus_can_be_deleted;
+    uc_klass->prepare_delete = can_bus_prepare_delete;
 }
 
 static const TypeInfo can_bus_info = {
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
index 7080f85f95..6faa0b2fd9 100644
--- a/qom/object_interfaces.c
+++ b/qom/object_interfaces.c
@@ -32,16 +32,15 @@ bool user_creatable_complete(UserCreatable *uc, Error **errp)
     return !*errp;
 }
 
-bool user_creatable_can_be_deleted(UserCreatable *uc)
+bool user_creatable_prepare_delete(UserCreatable *uc, Error **errp)
 {
-
     UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
+    ERRP_GUARD();
 
-    if (ucc->can_be_deleted) {
-        return ucc->can_be_deleted(uc);
-    } else {
-        return true;
+    if (ucc->prepare_delete) {
+        ucc->prepare_delete(uc, errp);
     }
+    return !*errp;
 }
 
 void user_creatable_add_qapi(ObjectOptions *options, Error **errp)
@@ -253,8 +252,7 @@ bool user_creatable_del(const char *id, Error **errp)
         return false;
     }
 
-    if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) {
-        error_setg(errp, "object '%s' is in use, can not be deleted", id);
+    if (!user_creatable_prepare_delete(USER_CREATABLE(obj), errp)) {
         return false;
     }
 
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
index f96610f510..e161bcfda9 100755
--- a/tests/qemu-iotests/245
+++ b/tests/qemu-iotests/245
@@ -801,7 +801,7 @@ class TestBlockdevReopen(iotests.QMPTestCase):
         # Now group1 is in use, it cannot be deleted
         result = self.vm.qmp('object-del', id = 'group1')
         self.assert_qmp(result, 'error/class', 'GenericError')
-        self.assert_qmp(result, 'error/desc', "object 'group1' is in use, can not be deleted")
+        self.assert_qmp(result, 'error/desc', "Throttle group still has multiple references")
 
         # Default options, this switches the group back to group0
         self.reopen(opts)
@@ -809,7 +809,7 @@ class TestBlockdevReopen(iotests.QMPTestCase):
         # So now we cannot delete group0
         result = self.vm.qmp('object-del', id = 'group0')
         self.assert_qmp(result, 'error/class', 'GenericError')
-        self.assert_qmp(result, 'error/desc', "object 'group0' is in use, can not be deleted")
+        self.assert_qmp(result, 'error/desc', "Throttle group still has multiple references")
 
         # But group1 is free this time, and it can be deleted
         self.vm.cmd('object-del', id = 'group1')
diff --git a/util/main-loop.c b/util/main-loop.c
index ad8645c30a..67ee06c311 100644
--- a/util/main-loop.c
+++ b/util/main-loop.c
@@ -218,8 +218,9 @@ static void main_loop_init(EventLoopBase *base, Error **errp)
     mloop = m;
 }
 
-static bool main_loop_can_be_deleted(EventLoopBase *base)
+static bool main_loop_prepare_delete(EventLoopBase *base, Error **errp)
 {
+    error_setg(errp, "Deleting main loop is not supported");
     return false;
 }
 
@@ -229,7 +230,7 @@ static void main_loop_class_init(ObjectClass *oc, const void *class_data)
 
     bc->init = main_loop_init;
     bc->update_params = main_loop_update_params;
-    bc->can_be_deleted = main_loop_can_be_deleted;
+    bc->prepare_delete = main_loop_prepare_delete;
 }
 
 static const TypeInfo main_loop_info = {
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 02/35] monitor: replace 'common' with 'parent_obj' in MonitorHMP
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé,
	Peter Krempa
In-Reply-To: <20260624173752.2928717-1-berrange@redhat.com>

The field name 'parent_obj' is standard practice for QOM structs
so align the HMP monitor.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dave@treblig.org>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 monitor/hmp-cmds.c         |  2 +-
 monitor/hmp.c              | 43 ++++++++++++++++++++------------------
 monitor/monitor-internal.h |  2 +-
 monitor/monitor.c          |  6 +++---
 monitor/qmp-cmds.c         | 10 ++++-----
 ui/ui-hmp-cmds.c           |  2 +-
 6 files changed, 34 insertions(+), 31 deletions(-)

diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 443b8c785d..e139caeba9 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -287,7 +287,7 @@ void hmp_info_sync_profile(Monitor *mon, const QDict *qdict)
 
 void hmp_info_history(Monitor *mon, const QDict *qdict)
 {
-    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
+    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, parent_obj);
     int i;
     const char *str;
 
diff --git a/monitor/hmp.c b/monitor/hmp.c
index cc4390486e..3dde52ddbe 100644
--- a/monitor/hmp.c
+++ b/monitor/hmp.c
@@ -48,9 +48,9 @@ static void monitor_command_cb(void *opaque, const char *cmdline,
 {
     MonitorHMP *mon = opaque;
 
-    monitor_suspend(&mon->common);
+    monitor_suspend(&mon->parent_obj);
     handle_hmp_command(mon, cmdline);
-    monitor_resume(&mon->common);
+    monitor_resume(&mon->parent_obj);
 }
 
 void monitor_read_command(MonitorHMP *mon, int show_prompt)
@@ -73,7 +73,7 @@ int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func,
         /* prompt is printed on return from the command handler */
         return 0;
     } else {
-        monitor_printf(&mon->common,
+        monitor_printf(&mon->parent_obj,
                        "terminal does not support password prompting\n");
         return -ENOTTY;
     }
@@ -695,7 +695,7 @@ static const HMPCommand *monitor_parse_command(MonitorHMP *hmp_mon,
                                                const char **cmdp,
                                                HMPCommand *table)
 {
-    Monitor *mon = &hmp_mon->common;
+    Monitor *mon = &hmp_mon->parent_obj;
     const char *p;
     const HMPCommand *cmd;
     char cmdname[256];
@@ -1188,35 +1188,37 @@ void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
 
     if (!cmd->cmd && !cmd->cmd_info_hrt) {
         /* FIXME: is it useful to try autoload modules here ??? */
-        monitor_printf(&mon->common, "Command \"%.*s\" is not available.\n",
+        monitor_printf(&mon->parent_obj, "Command \"%.*s\" is not available.\n",
                        (int)(cmdline - cmd_start), cmd_start);
         return;
     }
 
-    qdict = monitor_parse_arguments(&mon->common, &cmdline, cmd);
+    qdict = monitor_parse_arguments(&mon->parent_obj, &cmdline, cmd);
     if (!qdict) {
         while (cmdline > cmd_start && qemu_isspace(cmdline[-1])) {
             cmdline--;
         }
-        monitor_printf(&mon->common, "Try \"help %.*s\" for more information\n",
+        monitor_printf(&mon->parent_obj,
+                       "Try \"help %.*s\" for more information\n",
                        (int)(cmdline - cmd_start), cmd_start);
         return;
     }
 
     if (!cmd->coroutine) {
         /* old_mon is non-NULL when called from qmp_human_monitor_command() */
-        Monitor *old_mon = monitor_set_cur(qemu_coroutine_self(), &mon->common);
-        handle_hmp_command_exec(&mon->common, cmd, qdict);
+        Monitor *old_mon = monitor_set_cur(qemu_coroutine_self(),
+                                           &mon->parent_obj);
+        handle_hmp_command_exec(&mon->parent_obj, cmd, qdict);
         monitor_set_cur(qemu_coroutine_self(), old_mon);
     } else {
         HandleHmpCommandCo data = {
-            .mon = &mon->common,
+            .mon = &mon->parent_obj,
             .cmd = cmd,
             .qdict = qdict,
             .done = false,
         };
         Coroutine *co = qemu_coroutine_create(handle_hmp_command_co, &data);
-        monitor_set_cur(co, &mon->common);
+        monitor_set_cur(co, &mon->parent_obj);
         aio_co_enter(qemu_get_aio_context(), co);
         AIO_WAIT_WHILE_UNLOCKED(NULL, !data.done);
     }
@@ -1434,7 +1436,7 @@ cleanup:
 
 static void monitor_read(void *opaque, const uint8_t *buf, int size)
 {
-    MonitorHMP *mon = container_of(opaque, MonitorHMP, common);
+    MonitorHMP *mon = container_of(opaque, MonitorHMP, parent_obj);
     int i;
 
     if (mon->rs) {
@@ -1443,7 +1445,7 @@ static void monitor_read(void *opaque, const uint8_t *buf, int size)
         }
     } else {
         if (size == 0 || buf[size - 1] != 0) {
-            monitor_printf(&mon->common, "corrupted command\n");
+            monitor_printf(&mon->parent_obj, "corrupted command\n");
         } else {
             handle_hmp_command(mon, (char *)buf);
         }
@@ -1512,26 +1514,26 @@ static void G_GNUC_PRINTF(2, 3) monitor_readline_printf(void *opaque,
     MonitorHMP *mon = opaque;
     va_list ap;
     va_start(ap, fmt);
-    monitor_vprintf(&mon->common, fmt, ap);
+    monitor_vprintf(&mon->parent_obj, fmt, ap);
     va_end(ap);
 }
 
 static void monitor_readline_flush(void *opaque)
 {
     MonitorHMP *mon = opaque;
-    monitor_flush(&mon->common);
+    monitor_flush(&mon->parent_obj);
 }
 
 void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp)
 {
     MonitorHMP *mon = g_new0(MonitorHMP, 1);
 
-    if (!qemu_chr_fe_init(&mon->common.chr, chr, errp)) {
+    if (!qemu_chr_fe_init(&mon->parent_obj.chr, chr, errp)) {
         g_free(mon);
         return;
     }
 
-    monitor_data_init(&mon->common, false, false, false);
+    monitor_data_init(&mon->parent_obj, false, false, false);
 
     mon->use_readline = use_readline;
     if (mon->use_readline) {
@@ -1542,9 +1544,10 @@ void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp)
         monitor_read_command(mon, 0);
     }
 
-    qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_read,
-                             monitor_event, NULL, &mon->common, NULL, true);
-    monitor_list_append(&mon->common);
+    qemu_chr_fe_set_handlers(&mon->parent_obj.chr,
+                             monitor_can_read, monitor_read, monitor_event,
+                             NULL, &mon->parent_obj, NULL, true);
+    monitor_list_append(&mon->parent_obj);
 }
 
 /**
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index a5c4aba306..eb301ea796 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -128,7 +128,7 @@ struct Monitor {
 };
 
 struct MonitorHMP {
-    Monitor common;
+    Monitor parent_obj;
     bool use_readline;
     /*
      * State used only in the thread "owning" the monitor.
diff --git a/monitor/monitor.c b/monitor/monitor.c
index 00b93ed612..2a1b511ff4 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -132,7 +132,7 @@ static inline bool monitor_is_hmp_non_interactive(const Monitor *mon)
         return false;
     }
 
-    return !monitor_uses_readline(container_of(mon, MonitorHMP, common));
+    return !monitor_uses_readline(container_of(mon, MonitorHMP, parent_obj));
 }
 
 static gboolean monitor_unblocked(void *do_not_use, GIOCondition cond,
@@ -542,7 +542,7 @@ static void monitor_accept_input(void *opaque)
 
     qemu_mutex_lock(&mon->mon_lock);
     if (!monitor_is_qmp(mon) && mon->reset_seen) {
-        MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
+        MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, parent_obj);
         assert(hmp_mon->rs);
         readline_restart(hmp_mon->rs);
         qemu_mutex_unlock(&mon->mon_lock);
@@ -627,7 +627,7 @@ void monitor_data_destroy(Monitor *mon)
     if (monitor_is_qmp(mon)) {
         monitor_data_destroy_qmp(container_of(mon, MonitorQMP, common));
     } else {
-        readline_free(container_of(mon, MonitorHMP, common)->rs);
+        readline_free(container_of(mon, MonitorHMP, parent_obj)->rs);
     }
     g_string_free(mon->outbuf, true);
     qemu_mutex_destroy(&mon->mon_lock);
diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c
index 0c409c27dc..aa9ee8a391 100644
--- a/monitor/qmp-cmds.c
+++ b/monitor/qmp-cmds.c
@@ -168,10 +168,10 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
     char *output = NULL;
     MonitorHMP hmp = {};
 
-    monitor_data_init(&hmp.common, false, true, false);
+    monitor_data_init(&hmp.parent_obj, false, true, false);
 
     if (has_cpu_index) {
-        int ret = monitor_set_cpu(&hmp.common, cpu_index);
+        int ret = monitor_set_cpu(&hmp.parent_obj, cpu_index);
         if (ret < 0) {
             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
                        "a CPU number");
@@ -181,12 +181,12 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
 
     handle_hmp_command(&hmp, command_line);
 
-    WITH_QEMU_LOCK_GUARD(&hmp.common.mon_lock) {
-        output = g_strdup(hmp.common.outbuf->str);
+    WITH_QEMU_LOCK_GUARD(&hmp.parent_obj.mon_lock) {
+        output = g_strdup(hmp.parent_obj.outbuf->str);
     }
 
 out:
-    monitor_data_destroy(&hmp.common);
+    monitor_data_destroy(&hmp.parent_obj);
     return output;
 }
 
diff --git a/ui/ui-hmp-cmds.c b/ui/ui-hmp-cmds.c
index ee3e731d07..06f4030ce4 100644
--- a/ui/ui-hmp-cmds.c
+++ b/ui/ui-hmp-cmds.c
@@ -343,7 +343,7 @@ void hmp_change_vnc(Monitor *mon, const char *device, const char *target,
         return;
     }
     if (!arg) {
-        MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
+        MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, parent_obj);
         monitor_read_password(hmp_mon, hmp_change_read_arg, NULL);
     } else {
         qmp_change_vnc_password(arg, errp);
-- 
2.54.0



^ permalink raw reply related

* [PATCH v5 00/35] monitor: turn QMP and HMP into QOM objects
From: Daniel P. Berrangé @ 2026-06-24 17:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: devel, Marc-André Lureau, Markus Armbruster, Paolo Bonzini,
	Dr. David Alan Gilbert, Alex Bennée, Christian Brauner,
	Philippe Mathieu-Daudé, Daniel P. Berrangé

Conceptually -object and object_add/object_del should be sufficient
for essentially all QEMU configuration....if only we ported all our
internal custom backends/devices/etc to QOM. That is of course a big
job which is why it hasn't happened.

This series started with the premise that the monitor is one of the
easier areas to convert since we have no more than three classes,
a common base, and QMP and HMP subclasses[1]. So why not give it a
go and thus unlock the ability to dynamically create/delete monitors
in QMP/HMP.

This series does the conversion in a great many small steps to better
understand the implications at each stage.

The high level outcome of this series is

 * HMP and QMP monitors are QOM objects, 'monitor-hmp' and
   'monitor-qmp' respectively

 * Both can be cold plugged and hot plugged. QMP only, can
   also be hot unplugged.

 * '-mon' is obsolete, deprecated and replaced by '-object',
   but -monitor, -qmp and kept  as high level syntax sugar

 * QMP gains a concept of "close-action" which makes it
   possible to mark a monitor for auto-delete.

The monitor hot-unplug code and the qtest and functional testing
code is heavily derived from a series sent by Christian Brauner
which proposed new monitor_add/monitor_del commands:

  https://lists.nongnu.org/archive/html/qemu-devel/2026-04/msg01349.html

I left Christian's authorship & SoB on the patches which were
derived from his code, though the code has been refactored quite
a bit in places, so bugs are quite possibly my own.

Note that Christian's series allowed the use of "monitor_del"
commands against the current monitor session. ie a client could
delete the very monitor it was using. This is an awkward concept
as it needs special casing to delay the deletion to happen in
the background, such that that the QMP response to 'monitor_del'
could still be sent back. This also left the chardev was orphaned
as there's no way to run 'chardev_dev' in that usage pattern.

To provide an alternative mechanism to address the same use case,
this series introduces the 'close-action' concept mentioned above,
that allows hotplugging a monitor to service a specific task,
with the monitor being purged when the script closes its connection.
This avoids the special casing that an explicit "self deletion"
paradigm required.

While supporting hotplug of HMP was trivial, I didn't do any work
to think about hotunplug of HMP, since IMHO it is of limited value
given HMP's typical use cases.

[1] ~~~ we did all this not because it was easy,
        but because we thought it would be easy ~~~

Changed in v5:

 - Address another race when looking up monitor by ID
 - Refer to "line editting" when talking about HMP
   readline feature
 - Misc typos
 - Fix mis-placed setting of 'delete_pending'
 - Add test case to validate reconnecting to QMP

Changed in v4:

 - Hold reference into BH to avoid race with auto-delete

Changed in v3:

 - Removed unused 'dead' struct field
 - Make use of 'setup_pending' struct field across BH
 - Add missing free of chardev_id
 - Add missnig ERRP_GUARD in monitor_new_qmp
 - Misc docs typos / rephrasing
 - Moved docs patch to the end
 - Fixed docs about the default QOM ID naming for legacy
   monitor syntax
 - Fixed random sleep time calculation in tests

Christian Brauner (6):
  monitor: convert from oneshot BH to persistent BH
  monitor: reject attempts to delete the current monitor
  monitor: protect qemu_chr_fe_accept_input with monitor lock
  monitor: implement support for deleting QMP objects
  tests/qtest: add tests for dynamic monitor add/remove
  tests/functional: add e2e test for dynamic QMP monitor hotplug

Daniel P. Berrangé (29):
  qom: replace 'can_be_deleted' with 'prepare_delete'
  monitor: replace 'common' with 'parent_obj' in MonitorHMP
  monitor: replace 'common' with 'parent_obj' in MonitorQMP
  monitor: rename monitor_init* to monitor_new*
  monitor: minimal conversion of monitors to QOM
  monitor: add 'chardev' property to Monitor base class
  monitor: add 'readline' property to HMP Monitor class
  monitor: add 'pretty' property to QMP Monitor class
  monitor: remove 'skip_flush' field
  monitor: move monitor_data_(init|destroy) into QOM init/finalize
  monitor: use class methods for monitor_vprintf
  monitor: use class methods for monitor_qapi_event_emit
  monitor: use class methods for monitor_accept_input
  monitor: use class method for I/O thread request
  monitor: use dynamic cast in monitor_qmp_requests_pop_any_with_lock
  util: use dynamic cast in error vreport
  monitor: drop unused monitor_cur_is_qmp
  monitor: use dynamic cast in QMP commands
  monitor: use dynamic cast in monitor_is_hmp_non_interactive
  monitor: drop unused monitor_is_qmp method
  monitor: eliminate monitor_is_hmp_non_interactive method
  monitor: implement "user creatable" interface for adding monitors
  tests/functional: add a stress test for monitor hot unplug
  qom: add method for getting the "id" of a QOM object
  qom: add trace events for user creatable create/delete APIs
  monitor: add support for auto-deleting monitors upon close
  tests: switch from -mon to -object monitor-qmp
  qemu-options: document new monitor-hmp and monitor-qmp objects
  docs: mark '-mon' as deprecated in favour of -object

 MAINTAINERS                                   |   1 +
 backends/cryptodev.c                          |  10 +-
 backends/hostmem.c                            |   5 +-
 backends/iommufd.c                            |  10 +-
 block/throttle-groups.c                       |  10 +-
 chardev/char.c                                |   3 +-
 docs/about/deprecated.rst                     |  10 +
 docs/devel/writing-monitor-commands.rst       |   4 +-
 docs/system/arm/xenpvh.rst                    |   4 +-
 docs/system/i386/xen.rst                      |   3 +-
 docs/system/i386/xenpvh.rst                   |   4 +-
 event-loop-base.c                             |   8 +-
 gdbstub/system.c                              |   4 +-
 include/monitor/monitor.h                     |  23 +-
 include/qom/object.h                          |  10 +
 include/qom/object_interfaces.h               |  26 +-
 include/system/event-loop-base.h              |   2 +-
 migration/migration-hmp-cmds.c                |   5 +-
 monitor/hmp-cmds.c                            |   7 +-
 monitor/hmp.c                                 | 181 ++++++++--
 monitor/monitor-internal.h                    |  73 ++--
 monitor/monitor.c                             | 262 +++++++-------
 monitor/qmp-cmds-control.c                    |  12 +-
 monitor/qmp-cmds.c                            |  14 +-
 monitor/qmp.c                                 | 319 +++++++++++++++---
 net/can/can_core.c                            |   5 +-
 python/qemu/machine/machine.py                |   4 +-
 qapi/qom.json                                 |  62 ++++
 qemu-options.hx                               |  56 ++-
 qom/object.c                                  |  17 +
 qom/object_interfaces.c                       |  20 +-
 qom/trace-events                              |   5 +
 storage-daemon/qemu-storage-daemon.c          |   2 +-
 stubs/monitor-core.c                          |   5 -
 stubs/monitor-internal.c                      |   3 +-
 system/vl.c                                   |  12 +-
 tests/functional/generic/meson.build          |   1 +
 .../generic/test_monitor_hotplug.py           | 305 +++++++++++++++++
 tests/qemu-iotests/245                        |   4 +-
 tests/qtest/libqtest.c                        |   2 +-
 tests/qtest/qmp-test.c                        | 174 ++++++++++
 tests/unit/test-util-sockets.c                |   1 -
 tools/qemu-vnc/stubs.c                        |   5 -
 ui/ui-hmp-cmds.c                              |   2 +-
 util/error-report.c                           |  13 +-
 util/main-loop.c                              |   5 +-
 46 files changed, 1386 insertions(+), 327 deletions(-)
 create mode 100755 tests/functional/generic/test_monitor_hotplug.py

-- 
2.54.0



^ permalink raw reply

* Re: [PATCH v2] drm/bridge: analogix_dp: Fix PE/VS value shift mismatch during link training
From: Vicente Bergas @ 2026-06-24 17:38 UTC (permalink / raw)
  To: Damon Ding
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
	Dmitry Baryshkov, Heiko Stuebner, Marek Szyprowski, dri-devel,
	linux-kernel
In-Reply-To: <20260623023506.309858-1-damon.ding@rock-chips.com>

On Tue, Jun 23, 2026 at 4:35 AM Damon Ding <damon.ding@rock-chips.com> wrote:
>
> VS/PE values returned by drm_dp_get_adjust_request_voltage() and
> drm_dp_get_adjust_request_pre_emphasis() are already encoded to their
> native DPCD register bit positions. However, DPCD_VOLTAGE_SWING_SET /
> DPCD_PRE_EMPHASIS_SET macros perform an extra internal shift. Feeding
> the raw offset-bearing values directly leads to overlapping bitfields
> and invalid lane training configuration, causing link training failures
> and black screen.
>
> Add right shift using DP_TRAIN_*_SHIFT constants to strip the DPCD bit
> offsets before passing values to the SET macros and subsequent checks.
> Apply this fix for both clock recovery and adjust training code paths.
>
> Reported-by: Vicente Bergas <vicencb@gmail.com>
> Closes: https://lore.kernel.org/all/CAAMcf8D-d+5n=H44KeKBSqWY42m+o32W+mO-r15VqWNyYhJL7Q@mail.gmail.com/
> Fixes: d84b087c7662 ("drm/bridge: analogix_dp: Apply DP helper APIs to get adjusted voltages and pre-emphasises")
> Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
>
> ---
>
> Changes in v2:
> - Fix the ambiguous descriptions in commit msg.
> ---
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 7a85774aaac1..1d39a354c3d9 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -309,7 +309,9 @@ static void analogix_dp_get_adjust_training_lane(struct analogix_dp_device *dp,
>         lane_count = dp->link_train.lane_count;
>         for (lane = 0; lane < lane_count; lane++) {
>                 voltage_swing = drm_dp_get_adjust_request_voltage(link_status, lane);
> +               voltage_swing >>= DP_TRAIN_VOLTAGE_SWING_SHIFT;
>                 pre_emphasis = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
> +               pre_emphasis >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;
>                 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
>                                 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
>
> @@ -355,7 +357,9 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp)
>         for (lane = 0; lane < lane_count; lane++) {
>                 training_lane = analogix_dp_get_lane_link_training(dp, lane);
>                 voltage_swing = drm_dp_get_adjust_request_voltage(link_status, lane);
> +               voltage_swing >>= DP_TRAIN_VOLTAGE_SWING_SHIFT;
>                 pre_emphasis = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
> +               pre_emphasis >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;
>
>                 if (DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing &&
>                     DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis)
> --
> 2.34.1

Tested-by: Vicente Bergas

This patch was tested toghether with
[PATCH v1] drm/bridge: analogix_dp: Apply standard DP training delay helpers

Regards,
  Vicente.

^ permalink raw reply

* Re: [PATCH] MAINTAINERS: Update SH/SoCFPGA/USB email addresses
From: Quentin Schulz @ 2026-06-24 17:37 UTC (permalink / raw)
  To: Marek Vasut, u-boot; +Cc: Tom Rini
In-Reply-To: <20260624171428.33523-1-marek.vasut+renesas@mailbox.org>

Hi Marek,

On 6/24/26 7:13 PM, Marek Vasut wrote:
> Update the email addresses to a valid one.
> Use N: usb to match on all USB related bits.
> 

Reviewed-by: Quentin Schulz <quentin.schulz@cherry.de>

Thanks!
Quentin

^ permalink raw reply


This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.