diff mbox series

[v3,2/2] hw/char/serial: Convert to three-phase reset

Message ID 20250110230418.95571-3-philmd@linaro.org (mailing list archive)
State New
Headers show
Series hw/char/serial: Convert to three-phase reset | expand

Commit Message

Philippe Mathieu-Daudé Jan. 10, 2025, 11:04 p.m. UTC
Convert the TYPE_SERIAL (16550A UART) based devices
to three-phase reset.

Only local states are reset so use the ResetHold
handler, like other legacy devices.

TYPE_SERIAL is a plain QDev object:
- Implement and register ResetHold
- Remove call to serial_reset() in DeviceRealize
- Remove qemu_[un]register_reset() calls

For TYPE_ISA_SERIAL, TYPE_PCI_SERIAL (single and
multi):
- Implement and register ResetHold
- Call device_cold_reset(TYPE_SERIAL) in ResetHold

For TYPE_SERIAL_MM, since it is not on a QBus, we
register a global reset hook to reset the embedded
TYPE_SERIAL (see commits surrounding 751b4b7b4b7).

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/char/serial-isa.c       | 10 ++++++++++
 hw/char/serial-mm.c        | 11 +++++++++++
 hw/char/serial-pci-multi.c | 19 +++++++++++++++++++
 hw/char/serial-pci.c       | 12 ++++++++++++
 hw/char/serial.c           | 10 ++++------
 5 files changed, 56 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c
index 2e755eaf440..29894737c61 100644
--- a/hw/char/serial-isa.c
+++ b/hw/char/serial-isa.c
@@ -53,6 +53,14 @@  static const int isa_serial_irq[MAX_ISA_SERIAL_PORTS] = {
     4, 3, 4, 3
 };
 
+static void serial_isa_reset_hold(Object *obj, ResetType type)
+{
+    ISASerialState *isa = ISA_SERIAL(obj);
+    SerialState *s = &isa->state;
+
+    device_cold_reset(DEVICE(s));
+}
+
 static void serial_isa_realizefn(DeviceState *dev, Error **errp)
 {
     static int index;
@@ -123,11 +131,13 @@  static void serial_isa_class_initfn(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
 
     dc->realize = serial_isa_realizefn;
     dc->vmsd = &vmstate_isa_serial;
     adevc->build_dev_aml = serial_isa_build_aml;
     device_class_set_props(dc, serial_isa_properties);
+    rc->phases.hold = serial_isa_reset_hold;
     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
 }
 
diff --git a/hw/char/serial-mm.c b/hw/char/serial-mm.c
index 6338e7c0ba8..7208fbda526 100644
--- a/hw/char/serial-mm.c
+++ b/hw/char/serial-mm.c
@@ -29,6 +29,7 @@ 
 #include "migration/vmstate.h"
 #include "qapi/error.h"
 #include "hw/qdev-properties.h"
+#include "system/reset.h"
 
 static uint64_t serial_mm_read(void *opaque, hwaddr addr, unsigned size)
 {
@@ -82,6 +83,16 @@  static void serial_mm_realize(DeviceState *dev, Error **errp)
                           8 << smm->regshift);
     sysbus_init_mmio(SYS_BUS_DEVICE(smm), &s->io);
     sysbus_init_irq(SYS_BUS_DEVICE(smm), &smm->serial.irq);
+
+    /*
+     * Because this Device is not on any bus in the qbus tree (it is
+     * not a sysbus device and it's not on some other bus like a PCI
+     * bus) it will not be automatically reset by the 'reset the
+     * sysbus' hook registered by vl.c like most devices. So we must
+     * manually register a reset hook for it.
+     * TODO: there should be a better way to do this.
+     */
+    qemu_register_reset(resettable_cold_reset_fn, DEVICE(s));
 }
 
 static const VMStateDescription vmstate_serial_mm = {
diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c
index 54b6224f4da..4c7081198a0 100644
--- a/hw/char/serial-pci-multi.c
+++ b/hw/char/serial-pci-multi.c
@@ -90,6 +90,19 @@  static size_t multi_serial_get_port_count(PCIDeviceClass *pc)
     g_assert_not_reached();
 }
 
+static void multi_serial_pci_reset_hold(Object *obj, ResetType type)
+{
+    PCIDevice *dev = PCI_DEVICE(obj);
+    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
+    size_t nports = multi_serial_get_port_count(pc);
+
+    for (size_t i = 0; i < nports; i++) {
+        SerialState *s = &pci->state[i];
+
+        device_cold_reset(DEVICE(s));
+    }
+}
 
 static void multi_serial_pci_realize(PCIDevice *dev, Error **errp)
 {
@@ -150,6 +163,8 @@  static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+
     pc->realize = multi_serial_pci_realize;
     pc->exit = multi_serial_pci_exit;
     pc->vendor_id = PCI_VENDOR_ID_REDHAT;
@@ -159,12 +174,15 @@  static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
     dc->vmsd = &vmstate_pci_multi_serial;
     device_class_set_props(dc, multi_2x_serial_pci_properties);
     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+    rc->phases.hold = multi_serial_pci_reset_hold;
 }
 
 static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+
     pc->realize = multi_serial_pci_realize;
     pc->exit = multi_serial_pci_exit;
     pc->vendor_id = PCI_VENDOR_ID_REDHAT;
@@ -174,6 +192,7 @@  static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
     dc->vmsd = &vmstate_pci_multi_serial;
     device_class_set_props(dc, multi_4x_serial_pci_properties);
     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+    rc->phases.hold = multi_serial_pci_reset_hold;
 }
 
 static void multi_serial_init(Object *o)
diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c
index 4291bfc4e7f..e3e762d871c 100644
--- a/hw/char/serial-pci.c
+++ b/hw/char/serial-pci.c
@@ -44,6 +44,15 @@  struct PCISerialState {
 #define TYPE_PCI_SERIAL "pci-serial"
 OBJECT_DECLARE_SIMPLE_TYPE(PCISerialState, PCI_SERIAL)
 
+static void serial_pci_reset_hold(Object *obj, ResetType type)
+{
+    PCIDevice *dev = PCI_DEVICE(obj);
+    PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
+    SerialState *s = &pci->state;
+
+    device_cold_reset(DEVICE(s));
+}
+
 static void serial_pci_realize(PCIDevice *dev, Error **errp)
 {
     PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
@@ -89,6 +98,8 @@  static void serial_pci_class_initfn(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+
     pc->realize = serial_pci_realize;
     pc->exit = serial_pci_exit;
     pc->vendor_id = PCI_VENDOR_ID_REDHAT;
@@ -98,6 +109,7 @@  static void serial_pci_class_initfn(ObjectClass *klass, void *data)
     dc->vmsd = &vmstate_pci_serial;
     device_class_set_props(dc, serial_pci_properties);
     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+    rc->phases.hold = serial_pci_reset_hold;
 }
 
 static void serial_pci_init(Object *o)
diff --git a/hw/char/serial.c b/hw/char/serial.c
index cdff29ccee2..587f04c24ef 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -851,9 +851,9 @@  const VMStateDescription vmstate_serial = {
     }
 };
 
-static void serial_reset(void *opaque)
+static void serial_reset_hold(Object *obj, ResetType type)
 {
-    SerialState *s = opaque;
+    SerialState *s = (SerialState *)obj;
 
     if (s->watch_tag > 0) {
         g_source_remove(s->watch_tag);
@@ -928,13 +928,11 @@  static void serial_realize(DeviceState *dev, Error **errp)
     s->modem_status_poll = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) serial_update_msl, s);
 
     s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s);
-    qemu_register_reset(serial_reset, s);
 
     qemu_chr_fe_set_handlers(&s->chr, serial_can_receive1, serial_receive1,
                              serial_event, serial_be_change, s, NULL, true);
     fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
     fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
-    serial_reset(s);
 }
 
 static void serial_unrealize(DeviceState *dev)
@@ -949,8 +947,6 @@  static void serial_unrealize(DeviceState *dev)
 
     fifo8_destroy(&s->recv_fifo);
     fifo8_destroy(&s->xmit_fifo);
-
-    qemu_unregister_reset(serial_reset, s);
 }
 
 const MemoryRegionOps serial_io_ops = {
@@ -975,12 +971,14 @@  static const Property serial_properties[] = {
 static void serial_class_init(ObjectClass *klass, void* data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
 
     /* internal device for serialio/serialmm, not user-creatable */
     dc->user_creatable = false;
     dc->realize = serial_realize;
     dc->unrealize = serial_unrealize;
     device_class_set_props(dc, serial_properties);
+    rc->phases.hold = serial_reset_hold;
 }
 
 static const TypeInfo serial_info = {