[PATCH 3/8] hw/i2c: smbus: increase MAX_DATA_LEN

Titus Rwantare <[email protected]> Wed, 29 Jul 2026 23:13:18 +0000
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <[email protected]>
The 32 byte payload was raised to 255 for block reads in the SMBus 3.0
specification. SMBus does not provide a way for devices to declare which
version of the spec they are designed to so we must allow newer devices
to return as much data as they allow.

vsmstate_smbus_extended_data is added to avoid breaking migration.

Specification: https://smbus.org/specs/SMBus_3_3_20240512.pdf

> 6.5.7 Block Write/Read
The Block Write begins with a slave address and a write condition. After th=
e command code the host issues a byte count which describes how many more b=
ytes will follow in the message. If a slave has 20 bytes to send, the byte =
count field will have the value 20 (14h), followed by the 20 bytes of data.=
 The byte count does not include the PEC byte. The byte count may be 0. A B=
lock Read or Block Write is allowed to transfer a maximum of 255 data bytes=
.

Signed-off-by: Titus Rwantare <[email protected]>
---
 hw/i2c/smbus_slave.c         | 27 ++++++++++++++++++++++++++-
 include/hw/i2c/smbus_slave.h |  2 +-
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c
index cfb61c879e..5dd2c38af7 100644
--- a/hw/i2c/smbus_slave.c
+++ b/hw/i2c/smbus_slave.c
@@ -215,6 +215,26 @@ bool smbus_vmstate_needed(SMBusDevice *dev)
     return dev->mode !=3D SMBUS_IDLE;
 }
=20
+#define SMBUS_DATA_MAX_LEN_OLD    34
+static bool smbus_extended_needed(void *opaque)
+{
+    SMBusDevice *dev =3D opaque;
+    return dev->data_len > SMBUS_DATA_MAX_LEN_OLD;
+}
+
+static const VMStateDescription vmstate_smbus_extended_data =3D {
+    .name =3D TYPE_SMBUS_DEVICE"/extended",
+    .version_id =3D 1,
+    .minimum_version_id =3D 1,
+    .needed =3D smbus_extended_needed,
+    .fields =3D (const VMStateField[]) {
+        /* separately save [34..257) */
+        VMSTATE_UINT8_SUB_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN_=
OLD,
+            SMBUS_DATA_MAX_LEN - SMBUS_DATA_MAX_LEN_OLD),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 const VMStateDescription vmstate_smbus_device =3D {
     .name =3D TYPE_SMBUS_DEVICE,
     .version_id =3D 1,
@@ -223,8 +243,13 @@ const VMStateDescription vmstate_smbus_device =3D {
         VMSTATE_I2C_SLAVE(i2c, SMBusDevice),
         VMSTATE_INT32(mode, SMBusDevice),
         VMSTATE_INT32(data_len, SMBusDevice),
-        VMSTATE_UINT8_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN),
+        VMSTATE_UINT8_SUB_ARRAY(data_buf, SMBusDevice, 0,
+            SMBUS_DATA_MAX_LEN_OLD),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections =3D (const VMStateDescription * const[]) {
+        &vmstate_smbus_extended_data,
+        NULL
     }
 };
=20
diff --git a/include/hw/i2c/smbus_slave.h b/include/hw/i2c/smbus_slave.h
index 86bfe0a79e..59522ff1b1 100644
--- a/include/hw/i2c/smbus_slave.h
+++ b/include/hw/i2c/smbus_slave.h
@@ -64,7 +64,7 @@ struct SMBusDeviceClass {
     uint8_t (*receive_byte)(SMBusDevice *dev);
 };
=20
-#define SMBUS_DATA_MAX_LEN 34  /* command + len + 32 bytes of data.  */
+#define SMBUS_DATA_MAX_LEN 257  /* command + len + 255 bytes of data.  */
=20
 struct SMBusDevice {
     /* The SMBus protocol is implemented on top of I2C.  */
--=20
2.55.0.508.g3f0d502094-goog