diff mbox series

[4/4] hw/i2c: smbus: mux: Reset SMBusDevice state on reset

Message ID 20240110212641.1916202-5-komlodi@google.com
State New
Headers show
Series hw/i2c: smbus: Reset fixes | expand

Commit Message

Joe Komlodi Jan. 10, 2024, 9:26 p.m. UTC
When a reset happens, both the SMBusDevice and PCA954x class do their
variable resetting on an enter reset. Because of this, only the PCA954x
has its reset called, which can leave the SMBusDevice in a bad state if
it was in the middle of a transaction.

To fix this we add parent reset functions for the SMBusDevice class, and
have the mux class invoke it when it resets.

Signed-off-by: Joe Komlodi <komlodi@google.com>
---
 hw/i2c/i2c_mux_pca954x.c     | 5 +++++
 hw/i2c/smbus_slave.c         | 3 +++
 include/hw/i2c/smbus_slave.h | 1 +
 3 files changed, 9 insertions(+)
diff mbox series

Patch

diff --git a/hw/i2c/i2c_mux_pca954x.c b/hw/i2c/i2c_mux_pca954x.c
index db5db956a6..307359a518 100644
--- a/hw/i2c/i2c_mux_pca954x.c
+++ b/hw/i2c/i2c_mux_pca954x.c
@@ -159,8 +159,13 @@  static uint8_t pca954x_read_byte(SMBusDevice *d)
 static void pca954x_enter_reset(Object *obj, ResetType type)
 {
     Pca954xState *s = PCA954X(obj);
+    Pca954xClass *pc = PCA954X_GET_CLASS(obj);
+
     /* Reset will disable all channels. */
     pca954x_write(s, 0);
+    if (pc->parent.parent_phases.enter) {
+        pc->parent.parent_phases.enter(obj, type);
+    }
 }
 
 I2CBus *pca954x_i2c_get_bus(I2CSlave *mux, uint8_t channel)
diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c
index 58abde29de..81adab8f77 100644
--- a/hw/i2c/smbus_slave.c
+++ b/hw/i2c/smbus_slave.c
@@ -212,8 +212,11 @@  static void smbus_device_class_init(ObjectClass *klass, void *data)
 {
     I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
     ResettableClass *rc = RESETTABLE_CLASS(klass);
+    SMBusDeviceClass *sdc = SMBUS_DEVICE_CLASS(klass);
 
     rc->phases.enter = smbus_device_enter_reset;
+    resettable_class_set_parent_phases(rc, smbus_device_enter_reset, NULL, NULL,
+                                       &sdc->parent_phases);
     sc->event = smbus_i2c_event;
     sc->recv = smbus_i2c_recv;
     sc->send = smbus_i2c_send;
diff --git a/include/hw/i2c/smbus_slave.h b/include/hw/i2c/smbus_slave.h
index 86bfe0a79e..0dd14be178 100644
--- a/include/hw/i2c/smbus_slave.h
+++ b/include/hw/i2c/smbus_slave.h
@@ -35,6 +35,7 @@  OBJECT_DECLARE_TYPE(SMBusDevice, SMBusDeviceClass,
 
 struct SMBusDeviceClass {
     I2CSlaveClass parent_class;
+    ResettablePhases parent_phases;
 
     /*
      * An operation with no data, special in SMBus.