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

Joe Komlodi posted 4 patches 8 months, 2 weeks ago
Maintainers: Corey Minyard <cminyard@mvista.com>, Patrick Venture <venture@google.com>
There is a newer version of this series
[PATCH 4/4] hw/i2c: smbus: mux: Reset SMBusDevice state on reset
Posted by Joe Komlodi 8 months, 2 weeks ago
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 --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.
-- 
2.43.0.472.g3155946c3a-goog