* [Qemu-devel] [PATCH 01/19] i2c: Split smbus into parts
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 02/19] i2c: have I2C receive operation return uint8_t minyard
` (17 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
smbus.c and smbus.h had device side code, master side code, and
smbus.h has some smbus_eeprom.c definitions. Split them into
separate files.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
MAINTAINERS | 12 ++
hw/arm/aspeed.c | 2 +-
hw/i2c/Makefile.objs | 2 +-
hw/i2c/pm_smbus.c | 2 +-
hw/i2c/smbus_eeprom.c | 3 +-
hw/i2c/smbus_ich9.c | 2 -
hw/i2c/smbus_master.c | 165 ++++++++++++++++++++++
hw/i2c/{smbus.c => smbus_slave.c} | 153 +-------------------
hw/i386/pc_piix.c | 2 +-
hw/i386/pc_q35.c | 2 +-
hw/isa/vt82c686.c | 1 -
hw/mips/mips_fulong2e.c | 2 +-
hw/mips/mips_malta.c | 2 +-
hw/ppc/sam460ex.c | 2 +-
include/hw/i2c/pm_smbus.h | 2 +
include/hw/i2c/smbus_eeprom.h | 32 +++++
include/hw/i2c/smbus_master.h | 55 ++++++++
include/hw/i2c/{smbus.h => smbus_slave.h} | 37 +----
18 files changed, 285 insertions(+), 193 deletions(-)
create mode 100644 hw/i2c/smbus_master.c
rename hw/i2c/{smbus.c => smbus_slave.c} (65%)
create mode 100644 include/hw/i2c/smbus_eeprom.h
create mode 100644 include/hw/i2c/smbus_master.h
rename include/hw/i2c/{smbus.h => smbus_slave.h} (65%)
diff --git a/MAINTAINERS b/MAINTAINERS
index 59e1f24d68..aaa80d0b59 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2142,6 +2142,18 @@ M: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
S: Maintained
F: contrib/elf2dmp/
+I2C and SMBus
+M: Corey Minyard <cminyard@mvista.com>
+S: Maintained
+F: hw/i2c/core.c
+F: hw/i2c/smbus_slave.c
+F: hw/i2c/smbus_master.c
+F: hw/i2c/smbus_eeprom.c
+F: include/hw/i2c/i2c.h
+F: include/hw/i2c/smbus_master.h
+F: include/hw/i2c/smbus_slave.h
+F: include/hw/i2c/smbus_eeprom.h
+
Usermode Emulation
------------------
Overall
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 5158985482..996812498d 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -18,7 +18,7 @@
#include "hw/arm/aspeed.h"
#include "hw/arm/aspeed_soc.h"
#include "hw/boards.h"
-#include "hw/i2c/smbus.h"
+#include "hw/i2c/smbus_eeprom.h"
#include "qemu/log.h"
#include "sysemu/block-backend.h"
#include "hw/loader.h"
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 37cacde978..8973edfa22 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -1,4 +1,4 @@
-common-obj-$(CONFIG_I2C) += core.o smbus.o smbus_eeprom.o
+common-obj-$(CONFIG_I2C) += core.o smbus_slave.o smbus_master.o smbus_eeprom.o
common-obj-$(CONFIG_DDC) += i2c-ddc.o
common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o
diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 03062740cc..6cfb7eb1b3 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/i2c/pm_smbus.h"
-#include "hw/i2c/smbus.h"
+#include "hw/i2c/smbus_master.h"
#define SMBHSTSTS 0x00
#define SMBHSTCNT 0x02
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index f18aa3de35..d82423aa7e 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -25,7 +25,8 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/i2c/i2c.h"
-#include "hw/i2c/smbus.h"
+#include "hw/i2c/smbus_slave.h"
+#include "hw/i2c/smbus_eeprom.h"
//#define DEBUG
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index 2a8b49e02f..e6d8d28194 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -29,8 +29,6 @@
#include "hw/i2c/pm_smbus.h"
#include "hw/pci/pci.h"
#include "sysemu/sysemu.h"
-#include "hw/i2c/i2c.h"
-#include "hw/i2c/smbus.h"
#include "hw/i386/ich9.h"
diff --git a/hw/i2c/smbus_master.c b/hw/i2c/smbus_master.c
new file mode 100644
index 0000000000..0a6223744c
--- /dev/null
+++ b/hw/i2c/smbus_master.c
@@ -0,0 +1,165 @@
+/*
+ * QEMU SMBus host (master) emulation.
+ *
+ * This code emulates SMBus transactions from the master point of view,
+ * it runs the individual I2C transaction to do the SMBus protocol
+ * over I2C.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "hw/i2c/smbus_master.h"
+
+/* Master device commands. */
+int smbus_quick_command(I2CBus *bus, uint8_t addr, int read)
+{
+ if (i2c_start_transfer(bus, addr, read)) {
+ return -1;
+ }
+ i2c_end_transfer(bus);
+ return 0;
+}
+
+int smbus_receive_byte(I2CBus *bus, uint8_t addr)
+{
+ uint8_t data;
+
+ if (i2c_start_transfer(bus, addr, 1)) {
+ return -1;
+ }
+ data = i2c_recv(bus);
+ i2c_nack(bus);
+ i2c_end_transfer(bus);
+ return data;
+}
+
+int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data)
+{
+ if (i2c_start_transfer(bus, addr, 0)) {
+ return -1;
+ }
+ i2c_send(bus, data);
+ i2c_end_transfer(bus);
+ return 0;
+}
+
+int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command)
+{
+ uint8_t data;
+ if (i2c_start_transfer(bus, addr, 0)) {
+ return -1;
+ }
+ i2c_send(bus, command);
+ if (i2c_start_transfer(bus, addr, 1)) {
+ i2c_end_transfer(bus);
+ return -1;
+ }
+ data = i2c_recv(bus);
+ i2c_nack(bus);
+ i2c_end_transfer(bus);
+ return data;
+}
+
+int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data)
+{
+ if (i2c_start_transfer(bus, addr, 0)) {
+ return -1;
+ }
+ i2c_send(bus, command);
+ i2c_send(bus, data);
+ i2c_end_transfer(bus);
+ return 0;
+}
+
+int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command)
+{
+ uint16_t data;
+ if (i2c_start_transfer(bus, addr, 0)) {
+ return -1;
+ }
+ i2c_send(bus, command);
+ if (i2c_start_transfer(bus, addr, 1)) {
+ i2c_end_transfer(bus);
+ return -1;
+ }
+ data = i2c_recv(bus);
+ data |= i2c_recv(bus) << 8;
+ i2c_nack(bus);
+ i2c_end_transfer(bus);
+ return data;
+}
+
+int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data)
+{
+ if (i2c_start_transfer(bus, addr, 0)) {
+ return -1;
+ }
+ i2c_send(bus, command);
+ i2c_send(bus, data & 0xff);
+ i2c_send(bus, data >> 8);
+ i2c_end_transfer(bus);
+ return 0;
+}
+
+int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+ int len, bool recv_len, bool send_cmd)
+{
+ int rlen;
+ int i;
+
+ if (send_cmd) {
+ if (i2c_start_transfer(bus, addr, 0)) {
+ return -1;
+ }
+ i2c_send(bus, command);
+ }
+ if (i2c_start_transfer(bus, addr, 1)) {
+ if (send_cmd) {
+ i2c_end_transfer(bus);
+ }
+ return -1;
+ }
+ if (recv_len) {
+ rlen = i2c_recv(bus);
+ } else {
+ rlen = len;
+ }
+ if (rlen > len) {
+ rlen = 0;
+ }
+ for (i = 0; i < rlen; i++) {
+ data[i] = i2c_recv(bus);
+ }
+ i2c_nack(bus);
+ i2c_end_transfer(bus);
+ return rlen;
+}
+
+int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+ int len, bool send_len)
+{
+ int i;
+
+ if (len > 32) {
+ len = 32;
+ }
+
+ if (i2c_start_transfer(bus, addr, 0)) {
+ return -1;
+ }
+ i2c_send(bus, command);
+ if (send_len) {
+ i2c_send(bus, len);
+ }
+ for (i = 0; i < len; i++) {
+ i2c_send(bus, data[i]);
+ }
+ i2c_end_transfer(bus);
+ return 0;
+}
diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus_slave.c
similarity index 65%
rename from hw/i2c/smbus.c
rename to hw/i2c/smbus_slave.c
index 30028bfcc2..463fafe3c5 100644
--- a/hw/i2c/smbus.c
+++ b/hw/i2c/smbus_slave.c
@@ -1,6 +1,10 @@
/*
* QEMU SMBus device emulation.
*
+ * This code is a helper for SMBus device emulation. It implements an
+ * I2C device inteface and runs the SMBus protocol from the device
+ * point of view and maps those to simple calls to emulate.
+ *
* Copyright (c) 2007 CodeSourcery.
* Written by Paul Brook
*
@@ -12,7 +16,7 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/i2c/i2c.h"
-#include "hw/i2c/smbus.h"
+#include "hw/i2c/smbus_slave.h"
//#define DEBUG_SMBUS 1
@@ -206,153 +210,6 @@ static int smbus_i2c_send(I2CSlave *s, uint8_t data)
return 0;
}
-/* Master device commands. */
-int smbus_quick_command(I2CBus *bus, uint8_t addr, int read)
-{
- if (i2c_start_transfer(bus, addr, read)) {
- return -1;
- }
- i2c_end_transfer(bus);
- return 0;
-}
-
-int smbus_receive_byte(I2CBus *bus, uint8_t addr)
-{
- uint8_t data;
-
- if (i2c_start_transfer(bus, addr, 1)) {
- return -1;
- }
- data = i2c_recv(bus);
- i2c_nack(bus);
- i2c_end_transfer(bus);
- return data;
-}
-
-int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data)
-{
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, data);
- i2c_end_transfer(bus);
- return 0;
-}
-
-int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command)
-{
- uint8_t data;
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- if (i2c_start_transfer(bus, addr, 1)) {
- i2c_end_transfer(bus);
- return -1;
- }
- data = i2c_recv(bus);
- i2c_nack(bus);
- i2c_end_transfer(bus);
- return data;
-}
-
-int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data)
-{
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- i2c_send(bus, data);
- i2c_end_transfer(bus);
- return 0;
-}
-
-int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command)
-{
- uint16_t data;
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- if (i2c_start_transfer(bus, addr, 1)) {
- i2c_end_transfer(bus);
- return -1;
- }
- data = i2c_recv(bus);
- data |= i2c_recv(bus) << 8;
- i2c_nack(bus);
- i2c_end_transfer(bus);
- return data;
-}
-
-int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data)
-{
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- i2c_send(bus, data & 0xff);
- i2c_send(bus, data >> 8);
- i2c_end_transfer(bus);
- return 0;
-}
-
-int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
- int len, bool recv_len, bool send_cmd)
-{
- int rlen;
- int i;
-
- if (send_cmd) {
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- }
- if (i2c_start_transfer(bus, addr, 1)) {
- if (send_cmd) {
- i2c_end_transfer(bus);
- }
- return -1;
- }
- if (recv_len) {
- rlen = i2c_recv(bus);
- } else {
- rlen = len;
- }
- if (rlen > len) {
- rlen = 0;
- }
- for (i = 0; i < rlen; i++) {
- data[i] = i2c_recv(bus);
- }
- i2c_nack(bus);
- i2c_end_transfer(bus);
- return rlen;
-}
-
-int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
- int len, bool send_len)
-{
- int i;
-
- if (len > 32)
- len = 32;
-
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
- }
- i2c_send(bus, command);
- if (send_len) {
- i2c_send(bus, len);
- }
- for (i = 0; i < len; i++) {
- i2c_send(bus, data[i]);
- }
- i2c_end_transfer(bus);
- return 0;
-}
-
static void smbus_device_class_init(ObjectClass *klass, void *data)
{
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 63c84e3827..6ba163ccbb 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -42,7 +42,7 @@
#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
#include "sysemu/arch_init.h"
-#include "hw/i2c/smbus.h"
+#include "hw/i2c/smbus_eeprom.h"
#include "hw/xen/xen.h"
#include "exec/memory.h"
#include "exec/address-spaces.h"
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index b7b7959934..1689885cac 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -33,7 +33,7 @@
#include "hw/hw.h"
#include "hw/loader.h"
#include "sysemu/arch_init.h"
-#include "hw/i2c/smbus.h"
+#include "hw/i2c/smbus_eeprom.h"
#include "hw/boards.h"
#include "hw/timer/mc146818rtc.h"
#include "hw/xen/xen.h"
diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 7302f6d74b..85d0532dd5 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -14,7 +14,6 @@
#include "hw/hw.h"
#include "hw/isa/vt82c686.h"
#include "hw/i2c/i2c.h"
-#include "hw/i2c/smbus.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "hw/isa/superio.h"
diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c
index 2fbba32c48..dae8acc108 100644
--- a/hw/mips/mips_fulong2e.c
+++ b/hw/mips/mips_fulong2e.c
@@ -27,7 +27,7 @@
#include "hw/isa/superio.h"
#include "net/net.h"
#include "hw/boards.h"
-#include "hw/i2c/smbus.h"
+#include "hw/i2c/smbus_eeprom.h"
#include "hw/block/flash.h"
#include "hw/mips/mips.h"
#include "hw/mips/cpudevs.h"
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index c1cf0fe12e..1fb7170f5e 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -33,7 +33,7 @@
#include "hw/char/serial.h"
#include "net/net.h"
#include "hw/boards.h"
-#include "hw/i2c/smbus.h"
+#include "hw/i2c/smbus_eeprom.h"
#include "hw/block/flash.h"
#include "hw/mips/mips.h"
#include "hw/mips/cpudevs.h"
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
index 84ea592749..a04d471433 100644
--- a/hw/ppc/sam460ex.c
+++ b/hw/ppc/sam460ex.c
@@ -34,7 +34,7 @@
#include "hw/sysbus.h"
#include "hw/char/serial.h"
#include "hw/i2c/ppc4xx_i2c.h"
-#include "hw/i2c/smbus.h"
+#include "hw/i2c/smbus_eeprom.h"
#include "hw/usb/hcd-ehci.h"
#include "hw/ppc/fdt.h"
diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h
index 060d3c6ac0..6dd5b7040b 100644
--- a/include/hw/i2c/pm_smbus.h
+++ b/include/hw/i2c/pm_smbus.h
@@ -1,6 +1,8 @@
#ifndef PM_SMBUS_H
#define PM_SMBUS_H
+#include "hw/i2c/smbus_master.h"
+
#define PM_SMBUS_MAX_MSG_SIZE 32
typedef struct PMSMBus {
diff --git a/include/hw/i2c/smbus_eeprom.h b/include/hw/i2c/smbus_eeprom.h
new file mode 100644
index 0000000000..46fb1a37d6
--- /dev/null
+++ b/include/hw/i2c/smbus_eeprom.h
@@ -0,0 +1,32 @@
+/*
+ * QEMU SMBus EEPROM API
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_SMBUS_EEPROM_H
+#define HW_SMBUS_EEPROM_H
+
+#include "hw/i2c/i2c.h"
+
+void smbus_eeprom_init_one(I2CBus *bus, uint8_t address, uint8_t *eeprom_buf);
+void smbus_eeprom_init(I2CBus *bus, int nb_eeprom,
+ const uint8_t *eeprom_spd, int size);
+
+#endif
diff --git a/include/hw/i2c/smbus_master.h b/include/hw/i2c/smbus_master.h
new file mode 100644
index 0000000000..bb13bc423c
--- /dev/null
+++ b/include/hw/i2c/smbus_master.h
@@ -0,0 +1,55 @@
+/*
+ * QEMU SMBus host (master) API
+ *
+ * Copyright (c) 2007 Arastra, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_SMBUS_MASTER_H
+#define HW_SMBUS_MASTER_H
+
+#include "hw/i2c/i2c.h"
+
+/* Master device commands. */
+int smbus_quick_command(I2CBus *bus, uint8_t addr, int read);
+int smbus_receive_byte(I2CBus *bus, uint8_t addr);
+int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data);
+int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command);
+int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data);
+int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command);
+int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data);
+
+/*
+ * Do a block transfer from an I2C device. If recv_len is set, then the
+ * first received byte is a length field and is used to know how much data
+ * to receive. Otherwise receive "len" bytes. If send_cmd is set, send
+ * the command byte first before receiving the data.
+ */
+int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+ int len, bool recv_len, bool send_cmd);
+
+/*
+ * Do a block transfer to an I2C device. If send_len is set, send the
+ * "len" value before the data.
+ */
+int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+ int len, bool send_len);
+
+#endif
diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus_slave.h
similarity index 65%
rename from include/hw/i2c/smbus.h
rename to include/hw/i2c/smbus_slave.h
index 5c61c05999..46b8948f0f 100644
--- a/include/hw/i2c/smbus.h
+++ b/include/hw/i2c/smbus_slave.h
@@ -1,8 +1,5 @@
-#ifndef QEMU_SMBUS_H
-#define QEMU_SMBUS_H
-
/*
- * QEMU SMBus API
+ * QEMU SMBus device (slave) API
*
* Copyright (c) 2007 Arastra, Inc.
*
@@ -25,6 +22,9 @@
* THE SOFTWARE.
*/
+#ifndef HW_SMBUS_SLAVE_H
+#define HW_SMBUS_SLAVE_H
+
#include "hw/i2c/i2c.h"
#define TYPE_SMBUS_DEVICE "smbus-device"
@@ -66,33 +66,4 @@ struct SMBusDevice {
uint8_t command;
};
-/* Master device commands. */
-int smbus_quick_command(I2CBus *bus, uint8_t addr, int read);
-int smbus_receive_byte(I2CBus *bus, uint8_t addr);
-int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data);
-int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command);
-int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data);
-int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command);
-int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data);
-
-/*
- * Do a block transfer from an I2C device. If recv_len is set, then the
- * first received byte is a length field and is used to know how much data
- * to receive. Otherwise receive "len" bytes. If send_cmd is set, send
- * the command byte first before receiving the data.
- */
-int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
- int len, bool recv_len, bool send_cmd);
-
-/*
- * Do a block transfer to an I2C device. If send_len is set, send the
- * "len" value before the data.
- */
-int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
- int len, bool send_len);
-
-void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf);
-void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom,
- const uint8_t *eeprom_spd, int size);
-
#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 02/19] i2c: have I2C receive operation return uint8_t
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 01/19] i2c: Split smbus into parts minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 03/19] arm:i2c: Don't mask return from i2c_recv() minyard
` (16 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
It is never supposed to fail and cannot return an error, so just
have it return the proper type. Have it return 0xff on nothing
available, since that's what would happen on a real bus.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
hw/arm/pxa2xx.c | 2 +-
hw/arm/tosa.c | 4 ++--
hw/arm/z2.c | 2 +-
hw/audio/wm8750.c | 2 +-
hw/display/sii9022.c | 2 +-
hw/display/ssd0303.c | 4 ++--
hw/gpio/max7310.c | 2 +-
hw/i2c/core.c | 32 +++++++++++++-------------------
hw/i2c/i2c-ddc.c | 2 +-
hw/i2c/smbus_slave.c | 4 ++--
hw/input/lm832x.c | 2 +-
hw/misc/pca9552.c | 2 +-
hw/misc/tmp105.c | 2 +-
hw/misc/tmp421.c | 2 +-
hw/nvram/eeprom_at24c.c | 4 ++--
hw/timer/ds1338.c | 2 +-
hw/timer/m41t80.c | 2 +-
hw/timer/twl92230.c | 2 +-
include/hw/i2c/i2c.h | 7 +++----
19 files changed, 37 insertions(+), 44 deletions(-)
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index f598a1c053..3d7c88910e 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1286,7 +1286,7 @@ static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static int pxa2xx_i2c_rx(I2CSlave *i2c)
+static uint8_t pxa2xx_i2c_rx(I2CSlave *i2c)
{
PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
PXA2xxI2CState *s = slave->host;
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c
index 7a925fa5e6..eef9d427e7 100644
--- a/hw/arm/tosa.c
+++ b/hw/arm/tosa.c
@@ -197,10 +197,10 @@ static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static int tosa_dac_recv(I2CSlave *s)
+static uint8_t tosa_dac_recv(I2CSlave *s)
{
printf("%s: recv not supported!!!\n", __func__);
- return -1;
+ return 0xff;
}
static void tosa_tg_init(PXA2xxState *cpu)
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
index 697a822f1e..6f18d924df 100644
--- a/hw/arm/z2.c
+++ b/hw/arm/z2.c
@@ -243,7 +243,7 @@ static int aer915_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static int aer915_recv(I2CSlave *slave)
+static uint8_t aer915_recv(I2CSlave *slave)
{
AER915State *s = AER915(slave);
int retval = 0x00;
diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c
index f4aa838f62..169b006ade 100644
--- a/hw/audio/wm8750.c
+++ b/hw/audio/wm8750.c
@@ -561,7 +561,7 @@ static int wm8750_tx(I2CSlave *i2c, uint8_t data)
return 0;
}
-static int wm8750_rx(I2CSlave *i2c)
+static uint8_t wm8750_rx(I2CSlave *i2c)
{
return 0x00;
}
diff --git a/hw/display/sii9022.c b/hw/display/sii9022.c
index eaf11a6e7b..9994385c35 100644
--- a/hw/display/sii9022.c
+++ b/hw/display/sii9022.c
@@ -79,7 +79,7 @@ static int sii9022_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static int sii9022_rx(I2CSlave *i2c)
+static uint8_t sii9022_rx(I2CSlave *i2c)
{
sii9022_state *s = SII9022(i2c);
uint8_t res = 0x00;
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
index eb90ba26be..8edf34986c 100644
--- a/hw/display/ssd0303.c
+++ b/hw/display/ssd0303.c
@@ -62,10 +62,10 @@ typedef struct {
uint8_t framebuffer[132*8];
} ssd0303_state;
-static int ssd0303_recv(I2CSlave *i2c)
+static uint8_t ssd0303_recv(I2CSlave *i2c)
{
BADF("Reads not implemented\n");
- return -1;
+ return 0xff;
}
static int ssd0303_send(I2CSlave *i2c, uint8_t data)
diff --git a/hw/gpio/max7310.c b/hw/gpio/max7310.c
index 1a2478b5a9..c6f686c3eb 100644
--- a/hw/gpio/max7310.c
+++ b/hw/gpio/max7310.c
@@ -39,7 +39,7 @@ static void max7310_reset(DeviceState *dev)
s->command = 0x00;
}
-static int max7310_rx(I2CSlave *i2c)
+static uint8_t max7310_rx(I2CSlave *i2c)
{
MAX7310State *s = MAX7310(i2c);
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index b54725985a..15237ad073 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -191,23 +191,17 @@ int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send)
}
return ret ? -1 : 0;
} else {
- if ((QLIST_EMPTY(&bus->current_devs)) || (bus->broadcast)) {
- return -1;
- }
-
- sc = I2C_SLAVE_GET_CLASS(QLIST_FIRST(&bus->current_devs)->elt);
- if (sc->recv) {
- s = QLIST_FIRST(&bus->current_devs)->elt;
- ret = sc->recv(s);
- trace_i2c_recv(s->address, ret);
- if (ret < 0) {
- return ret;
- } else {
- *data = ret;
- return 0;
+ ret = 0xff;
+ if (!QLIST_EMPTY(&bus->current_devs) && !bus->broadcast) {
+ sc = I2C_SLAVE_GET_CLASS(QLIST_FIRST(&bus->current_devs)->elt);
+ if (sc->recv) {
+ s = QLIST_FIRST(&bus->current_devs)->elt;
+ ret = sc->recv(s);
+ trace_i2c_recv(s->address, ret);
}
}
- return -1;
+ *data = ret;
+ return 0;
}
}
@@ -216,12 +210,12 @@ int i2c_send(I2CBus *bus, uint8_t data)
return i2c_send_recv(bus, &data, true);
}
-int i2c_recv(I2CBus *bus)
+uint8_t i2c_recv(I2CBus *bus)
{
- uint8_t data;
- int ret = i2c_send_recv(bus, &data, false);
+ uint8_t data = 0xff;
- return ret < 0 ? ret : data;
+ i2c_send_recv(bus, &data, false);
+ return data;
}
void i2c_nack(I2CBus *bus)
diff --git a/hw/i2c/i2c-ddc.c b/hw/i2c/i2c-ddc.c
index 0a0367ff38..7aa8727771 100644
--- a/hw/i2c/i2c-ddc.c
+++ b/hw/i2c/i2c-ddc.c
@@ -51,7 +51,7 @@ static int i2c_ddc_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static int i2c_ddc_rx(I2CSlave *i2c)
+static uint8_t i2c_ddc_rx(I2CSlave *i2c)
{
I2CDDCState *s = I2CDDC(i2c);
diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c
index 463fafe3c5..6e4d542f51 100644
--- a/hw/i2c/smbus_slave.c
+++ b/hw/i2c/smbus_slave.c
@@ -156,11 +156,11 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
return 0;
}
-static int smbus_i2c_recv(I2CSlave *s)
+static uint8_t smbus_i2c_recv(I2CSlave *s)
{
SMBusDevice *dev = SMBUS_DEVICE(s);
SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
- int ret;
+ uint8_t ret;
switch (dev->mode) {
case SMBUS_RECV_BYTE:
diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c
index cffbf586d4..1fc7b86f19 100644
--- a/hw/input/lm832x.c
+++ b/hw/input/lm832x.c
@@ -401,7 +401,7 @@ static int lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static int lm_i2c_rx(I2CSlave *i2c)
+static uint8_t lm_i2c_rx(I2CSlave *i2c)
{
LM823KbdState *s = LM8323(i2c);
diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c
index 9775d5274a..7325d3f287 100644
--- a/hw/misc/pca9552.c
+++ b/hw/misc/pca9552.c
@@ -115,7 +115,7 @@ static void pca9552_autoinc(PCA9552State *s)
}
}
-static int pca9552_recv(I2CSlave *i2c)
+static uint8_t pca9552_recv(I2CSlave *i2c)
{
PCA9552State *s = PCA9552(i2c);
uint8_t ret;
diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c
index f6d7163273..0c32f6f8b6 100644
--- a/hw/misc/tmp105.c
+++ b/hw/misc/tmp105.c
@@ -147,7 +147,7 @@ static void tmp105_write(TMP105State *s)
}
}
-static int tmp105_rx(I2CSlave *i2c)
+static uint8_t tmp105_rx(I2CSlave *i2c)
{
TMP105State *s = TMP105(i2c);
diff --git a/hw/misc/tmp421.c b/hw/misc/tmp421.c
index eeb11000f0..ce6d40ac9c 100644
--- a/hw/misc/tmp421.c
+++ b/hw/misc/tmp421.c
@@ -249,7 +249,7 @@ static void tmp421_write(TMP421State *s)
}
}
-static int tmp421_rx(I2CSlave *i2c)
+static uint8_t tmp421_rx(I2CSlave *i2c)
{
TMP421State *s = TMP421(i2c);
diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c
index 27cd01e615..d1456dafbd 100644
--- a/hw/nvram/eeprom_at24c.c
+++ b/hw/nvram/eeprom_at24c.c
@@ -74,10 +74,10 @@ int at24c_eeprom_event(I2CSlave *s, enum i2c_event event)
}
static
-int at24c_eeprom_recv(I2CSlave *s)
+uint8_t at24c_eeprom_recv(I2CSlave *s)
{
EEPROMState *ee = AT24C_EE(s);
- int ret;
+ uint8_t ret;
ret = ee->mem[ee->cur];
diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index 3849b74a68..03da75486b 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -117,7 +117,7 @@ static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static int ds1338_recv(I2CSlave *i2c)
+static uint8_t ds1338_recv(I2CSlave *i2c)
{
DS1338State *s = DS1338(i2c);
uint8_t res;
diff --git a/hw/timer/m41t80.c b/hw/timer/m41t80.c
index 734d7d95fc..c45b9297d8 100644
--- a/hw/timer/m41t80.c
+++ b/hw/timer/m41t80.c
@@ -40,7 +40,7 @@ static int m41t80_send(I2CSlave *i2c, uint8_t data)
return 0;
}
-static int m41t80_recv(I2CSlave *i2c)
+static uint8_t m41t80_recv(I2CSlave *i2c)
{
M41t80State *s = M41T80(i2c);
struct tm now;
diff --git a/hw/timer/twl92230.c b/hw/timer/twl92230.c
index 51ec355f3f..c83d803dd8 100644
--- a/hw/timer/twl92230.c
+++ b/hw/timer/twl92230.c
@@ -737,7 +737,7 @@ static int menelaus_tx(I2CSlave *i2c, uint8_t data)
return 0;
}
-static int menelaus_rx(I2CSlave *i2c)
+static uint8_t menelaus_rx(I2CSlave *i2c)
{
MenelausState *s = TWL92230(i2c);
diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
index cf4c45a98f..8e236f7bb4 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -33,10 +33,9 @@ typedef struct I2CSlaveClass {
/*
* Slave to master. This cannot fail, the device should always
- * return something here. Negative values probably result in 0xff
- * and a possible log from the driver, and shouldn't be used.
+ * return something here.
*/
- int (*recv)(I2CSlave *s);
+ uint8_t (*recv)(I2CSlave *s);
/*
* Notify the slave of a bus state change. For start event,
@@ -78,7 +77,7 @@ void i2c_end_transfer(I2CBus *bus);
void i2c_nack(I2CBus *bus);
int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send);
int i2c_send(I2CBus *bus, uint8_t data);
-int i2c_recv(I2CBus *bus);
+uint8_t i2c_recv(I2CBus *bus);
DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr);
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 03/19] arm:i2c: Don't mask return from i2c_recv()
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 01/19] i2c: Split smbus into parts minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 02/19] i2c: have I2C receive operation return uint8_t minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 04/19] i2c: Don't check return value " minyard
` (15 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
It can't fail, and now that it returns a uint8_t a 0xff mask
is unnecessary.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/stellaris.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index 442529cc65..7b45fe3ccf 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -811,7 +811,7 @@ static void stellaris_i2c_write(void *opaque, hwaddr offset,
/* TODO: Handle errors. */
if (s->msa & 1) {
/* Recv */
- s->mdr = i2c_recv(s->bus) & 0xff;
+ s->mdr = i2c_recv(s->bus);
} else {
/* Send */
i2c_send(s->bus, s->mdr);
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 04/19] i2c: Don't check return value from i2c_recv()
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (2 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 03/19] arm:i2c: Don't mask return from i2c_recv() minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 05/19] i2c:smbus: Correct the working of quick commands minyard
` (14 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
i2c_recv() cannot fail, so there is no need to check the return
value. It also returns unt8_t, so comparing with < 0 is not
meaningful.
Fix up various I2C controllers to remove the unneeded code.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/i2c/aspeed_i2c.c | 9 ++-------
hw/i2c/exynos4210_i2c.c | 8 +-------
hw/i2c/imx_i2c.c | 12 ++----------
3 files changed, 5 insertions(+), 24 deletions(-)
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index a2dfa82760..a085510cfd 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -189,16 +189,11 @@ static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus)
static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus)
{
- int ret;
+ uint8_t ret;
aspeed_i2c_set_state(bus, I2CD_MRXD);
ret = i2c_recv(bus->bus);
- if (ret < 0) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: read failed\n", __func__);
- ret = 0xff;
- } else {
- bus->intr_status |= I2CD_INTR_RX_DONE;
- }
+ bus->intr_status |= I2CD_INTR_RX_DONE;
bus->buf = (ret & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT;
if (bus->cmd & I2CD_M_S_RX_CMD_LAST) {
i2c_nack(bus->bus);
diff --git a/hw/i2c/exynos4210_i2c.c b/hw/i2c/exynos4210_i2c.c
index c96fa7d7be..d154b05739 100644
--- a/hw/i2c/exynos4210_i2c.c
+++ b/hw/i2c/exynos4210_i2c.c
@@ -106,16 +106,10 @@ static inline void exynos4210_i2c_raise_interrupt(Exynos4210I2CState *s)
static void exynos4210_i2c_data_receive(void *opaque)
{
Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
- int ret;
s->i2cstat &= ~I2CSTAT_LAST_BIT;
s->scl_free = false;
- ret = i2c_recv(s->bus);
- if (ret < 0 && (s->i2ccon & I2CCON_ACK_GEN)) {
- s->i2cstat |= I2CSTAT_LAST_BIT; /* Data is not acknowledged */
- } else {
- s->i2cds = ret;
- }
+ s->i2cds = i2c_recv(s->bus);
exynos4210_i2c_raise_interrupt(s);
}
diff --git a/hw/i2c/imx_i2c.c b/hw/i2c/imx_i2c.c
index 6c81b98ebd..6da5224e2e 100644
--- a/hw/i2c/imx_i2c.c
+++ b/hw/i2c/imx_i2c.c
@@ -120,7 +120,7 @@ static uint64_t imx_i2c_read(void *opaque, hwaddr offset,
value = s->i2dr_read;
if (imx_i2c_is_master(s)) {
- int ret = 0xff;
+ uint8_t ret = 0xff;
if (s->address == ADDR_RESET) {
/* something is wrong as the address is not set */
@@ -133,15 +133,7 @@ static uint64_t imx_i2c_read(void *opaque, hwaddr offset,
} else {
/* get the next byte */
ret = i2c_recv(s->bus);
-
- if (ret >= 0) {
- imx_i2c_raise_interrupt(s);
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: read failed "
- "for device 0x%02x\n", TYPE_IMX_I2C,
- __func__, s->address);
- ret = 0xff;
- }
+ imx_i2c_raise_interrupt(s);
}
s->i2dr_read = ret;
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 05/19] i2c:smbus: Correct the working of quick commands
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (3 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 04/19] i2c: Don't check return value " minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 06/19] i2c:smbus: Simplify write operation minyard
` (13 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
The logic of handling quick SMBus commands was wrong. If you get a
finish event with no data, that's a quick command.
Document the quick command while we are at it.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
hw/i2c/smbus_slave.c | 35 +++++++++++++++++++----------------
include/hw/i2c/smbus_slave.h | 5 +++++
2 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c
index 6e4d542f51..6a89a286e3 100644
--- a/hw/i2c/smbus_slave.c
+++ b/hw/i2c/smbus_slave.c
@@ -54,9 +54,7 @@ static void smbus_do_write(SMBusDevice *dev)
{
SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
- if (dev->data_len == 0) {
- smbus_do_quick_cmd(dev, 0);
- } else if (dev->data_len == 1) {
+ if (dev->data_len == 1) {
DPRINTF("Send Byte\n");
if (sc->send_byte) {
sc->send_byte(dev, dev->data_buf[0]);
@@ -120,19 +118,24 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
break;
case I2C_FINISH:
- switch (dev->mode) {
- case SMBUS_WRITE_DATA:
- smbus_do_write(dev);
- break;
- case SMBUS_RECV_BYTE:
- smbus_do_quick_cmd(dev, 1);
- break;
- case SMBUS_READ_DATA:
- BADF("Unexpected stop during receive\n");
- break;
- default:
- /* Nothing to do. */
- break;
+ if (dev->data_len == 0) {
+ if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) {
+ smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA);
+ }
+ } else {
+ switch (dev->mode) {
+ case SMBUS_WRITE_DATA:
+ smbus_do_write(dev);
+ break;
+
+ case SMBUS_READ_DATA:
+ BADF("Unexpected stop during receive\n");
+ break;
+
+ default:
+ /* Nothing to do. */
+ break;
+ }
}
dev->mode = SMBUS_IDLE;
dev->data_len = 0;
diff --git a/include/hw/i2c/smbus_slave.h b/include/hw/i2c/smbus_slave.h
index 46b8948f0f..5ef1c72ad0 100644
--- a/include/hw/i2c/smbus_slave.h
+++ b/include/hw/i2c/smbus_slave.h
@@ -40,6 +40,11 @@ typedef struct SMBusDevice SMBusDevice;
typedef struct SMBusDeviceClass
{
I2CSlaveClass parent_class;
+
+ /*
+ * An operation with no data, special in SMBus.
+ * This may be NULL, quick commands are ignore in that case.
+ */
void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
void (*send_byte)(SMBusDevice *dev, uint8_t val);
uint8_t (*receive_byte)(SMBusDevice *dev);
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 06/19] i2c:smbus: Simplify write operation
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (4 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 05/19] i2c:smbus: Correct the working of quick commands minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 07/19] i2c:smbus: Simplify read handling minyard
` (12 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
There were two different write functions and the SMBus code kept
track of the command.
Keeping track of the command wasn't useful, in fact it wasn't quite
correct for the eeprom_smbus code. And there is no need for two write
functions. Just have one write function and the first byte in the
buffer is the command.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
hw/i2c/smbus_eeprom.c | 47 ++++++++++++------------------------
hw/i2c/smbus_slave.c | 25 ++++---------------
include/hw/i2c/smbus_slave.h | 21 ++++++++++------
3 files changed, 34 insertions(+), 59 deletions(-)
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index d82423aa7e..3f9ed266f8 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -43,16 +43,6 @@ static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read)
#endif
}
-static void eeprom_send_byte(SMBusDevice *dev, uint8_t val)
-{
- SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
-#ifdef DEBUG
- printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n",
- dev->i2c.address, val);
-#endif
- eeprom->offset = val;
-}
-
static uint8_t eeprom_receive_byte(SMBusDevice *dev)
{
SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
@@ -65,34 +55,30 @@ static uint8_t eeprom_receive_byte(SMBusDevice *dev)
return val;
}
-static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len)
+static int eeprom_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len)
{
SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
- int n;
+ uint8_t *data = eeprom->data;
+
#ifdef DEBUG
printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
- dev->i2c.address, cmd, buf[0]);
+ dev->i2c.address, buf[0], buf[1]);
#endif
- /* A page write operation is not a valid SMBus command.
- It is a block write without a length byte. Fortunately we
- get the full block anyway. */
- /* TODO: Should this set the current location? */
- if (cmd + len > 256)
- n = 256 - cmd;
- else
- n = len;
- memcpy(eeprom->data + cmd, buf, n);
- len -= n;
- if (len)
- memcpy(eeprom->data, buf + n, len);
+ /* len is guaranteed to be > 0 */
+ eeprom->offset = buf[0];
+ buf++;
+ len--;
+
+ for (; len > 0; len--) {
+ data[eeprom->offset] = *buf++;
+ eeprom->offset = (eeprom->offset + 1) % 256;
+ }
+
+ return 0;
}
-static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n)
+static uint8_t eeprom_read_data(SMBusDevice *dev, int n)
{
- SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
- /* If this is the first byte then set the current position. */
- if (n == 0)
- eeprom->offset = cmd;
/* As with writes, we implement block reads without the
SMBus length byte. */
return eeprom_receive_byte(dev);
@@ -117,7 +103,6 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
dc->realize = smbus_eeprom_realize;
sc->quick_cmd = eeprom_quick_cmd;
- sc->send_byte = eeprom_send_byte;
sc->receive_byte = eeprom_receive_byte;
sc->write_data = eeprom_write_data;
sc->read_data = eeprom_read_data;
diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c
index 6a89a286e3..92c7a5086c 100644
--- a/hw/i2c/smbus_slave.c
+++ b/hw/i2c/smbus_slave.c
@@ -54,18 +54,9 @@ static void smbus_do_write(SMBusDevice *dev)
{
SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
- if (dev->data_len == 1) {
- DPRINTF("Send Byte\n");
- if (sc->send_byte) {
- sc->send_byte(dev, dev->data_buf[0]);
- }
- } else {
- dev->command = dev->data_buf[0];
- DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
- if (sc->write_data) {
- sc->write_data(dev, dev->command, dev->data_buf + 1,
- dev->data_len - 1);
- }
+ DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len);
+ if (sc->write_data) {
+ sc->write_data(dev, dev->data_buf, dev->data_len);
}
}
@@ -98,13 +89,7 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
BADF("Read after write with no data\n");
dev->mode = SMBUS_CONFUSED;
} else {
- if (dev->data_len > 1) {
- smbus_do_write(dev);
- } else {
- dev->command = dev->data_buf[0];
- DPRINTF("%02x: Command %d\n", dev->i2c.address,
- dev->command);
- }
+ smbus_do_write(dev);
DPRINTF("Read mode\n");
dev->data_len = 0;
dev->mode = SMBUS_READ_DATA;
@@ -177,7 +162,7 @@ static uint8_t smbus_i2c_recv(I2CSlave *s)
break;
case SMBUS_READ_DATA:
if (sc->read_data) {
- ret = sc->read_data(dev, dev->command, dev->data_len);
+ ret = sc->read_data(dev, dev->data_len);
dev->data_len++;
} else {
ret = 0;
diff --git a/include/hw/i2c/smbus_slave.h b/include/hw/i2c/smbus_slave.h
index 5ef1c72ad0..fa92201ec6 100644
--- a/include/hw/i2c/smbus_slave.h
+++ b/include/hw/i2c/smbus_slave.h
@@ -46,18 +46,24 @@ typedef struct SMBusDeviceClass
* This may be NULL, quick commands are ignore in that case.
*/
void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
- void (*send_byte)(SMBusDevice *dev, uint8_t val);
+
uint8_t (*receive_byte)(SMBusDevice *dev);
- /* We can't distinguish between a word write and a block write with
- length 1, so pass the whole data block including the length byte
- (if present). The device is responsible figuring out what type of
- command this is. */
- void (*write_data)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len);
+
+ /*
+ * We can't distinguish between a word write and a block write with
+ * length 1, so pass the whole data block including the length byte
+ * (if present). The device is responsible figuring out what type of
+ * command this is.
+ * This may be NULL if no data is written to the device. Writes
+ * will be ignore in that case.
+ */
+ int (*write_data)(SMBusDevice *dev, uint8_t *buf, uint8_t len);
+
/* Likewise we can't distinguish between different reads, or even know
the length of the read until the read is complete, so read data a
byte at a time. The device is responsible for adding the length
byte on block reads. */
- uint8_t (*read_data)(SMBusDevice *dev, uint8_t cmd, int n);
+ uint8_t (*read_data)(SMBusDevice *dev, int n);
} SMBusDeviceClass;
struct SMBusDevice {
@@ -68,7 +74,6 @@ struct SMBusDevice {
int mode;
int data_len;
uint8_t data_buf[34]; /* command + len + 32 bytes of data. */
- uint8_t command;
};
#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 07/19] i2c:smbus: Simplify read handling
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (5 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 06/19] i2c:smbus: Simplify write operation minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 08/19] i2c:smbus_eeprom: Get rid of the quick command minyard
` (11 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
There were two different read functions, and with the removal of
the command passed in there is no functional difference. So remove
one of them. With that you don't need one of the states, so that
can be removed, too.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
hw/i2c/smbus_eeprom.c | 8 --------
hw/i2c/smbus_slave.c | 21 +++------------------
include/hw/i2c/smbus_slave.h | 17 ++++++++++-------
3 files changed, 13 insertions(+), 33 deletions(-)
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index 3f9ed266f8..c2b9e3383e 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -77,13 +77,6 @@ static int eeprom_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len)
return 0;
}
-static uint8_t eeprom_read_data(SMBusDevice *dev, int n)
-{
- /* As with writes, we implement block reads without the
- SMBus length byte. */
- return eeprom_receive_byte(dev);
-}
-
static void smbus_eeprom_realize(DeviceState *dev, Error **errp)
{
SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev;
@@ -105,7 +98,6 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
sc->quick_cmd = eeprom_quick_cmd;
sc->receive_byte = eeprom_receive_byte;
sc->write_data = eeprom_write_data;
- sc->read_data = eeprom_read_data;
dc->props = smbus_eeprom_properties;
/* Reason: pointer property "data" */
dc->user_creatable = false;
diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c
index 92c7a5086c..52a57423ee 100644
--- a/hw/i2c/smbus_slave.c
+++ b/hw/i2c/smbus_slave.c
@@ -34,7 +34,6 @@ do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
enum {
SMBUS_IDLE,
SMBUS_WRITE_DATA,
- SMBUS_RECV_BYTE,
SMBUS_READ_DATA,
SMBUS_DONE,
SMBUS_CONFUSED = -1
@@ -82,7 +81,7 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
switch (dev->mode) {
case SMBUS_IDLE:
DPRINTF("Read mode\n");
- dev->mode = SMBUS_RECV_BYTE;
+ dev->mode = SMBUS_READ_DATA;
break;
case SMBUS_WRITE_DATA:
if (dev->data_len == 0) {
@@ -91,7 +90,6 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
} else {
smbus_do_write(dev);
DPRINTF("Read mode\n");
- dev->data_len = 0;
dev->mode = SMBUS_READ_DATA;
}
break;
@@ -148,31 +146,18 @@ static uint8_t smbus_i2c_recv(I2CSlave *s)
{
SMBusDevice *dev = SMBUS_DEVICE(s);
SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
- uint8_t ret;
+ uint8_t ret = 0xff;
switch (dev->mode) {
- case SMBUS_RECV_BYTE:
+ case SMBUS_READ_DATA:
if (sc->receive_byte) {
ret = sc->receive_byte(dev);
- } else {
- ret = 0;
- }
- DPRINTF("Receive Byte %02x\n", ret);
- dev->mode = SMBUS_DONE;
- break;
- case SMBUS_READ_DATA:
- if (sc->read_data) {
- ret = sc->read_data(dev, dev->data_len);
- dev->data_len++;
- } else {
- ret = 0;
}
DPRINTF("Read data %02x\n", ret);
break;
default:
BADF("Unexpected read in state %d\n", dev->mode);
dev->mode = SMBUS_CONFUSED;
- ret = 0;
break;
}
return ret;
diff --git a/include/hw/i2c/smbus_slave.h b/include/hw/i2c/smbus_slave.h
index fa92201ec6..79050fb92d 100644
--- a/include/hw/i2c/smbus_slave.h
+++ b/include/hw/i2c/smbus_slave.h
@@ -47,8 +47,6 @@ typedef struct SMBusDeviceClass
*/
void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
- uint8_t (*receive_byte)(SMBusDevice *dev);
-
/*
* We can't distinguish between a word write and a block write with
* length 1, so pass the whole data block including the length byte
@@ -59,11 +57,16 @@ typedef struct SMBusDeviceClass
*/
int (*write_data)(SMBusDevice *dev, uint8_t *buf, uint8_t len);
- /* Likewise we can't distinguish between different reads, or even know
- the length of the read until the read is complete, so read data a
- byte at a time. The device is responsible for adding the length
- byte on block reads. */
- uint8_t (*read_data)(SMBusDevice *dev, int n);
+ /*
+ * Likewise we can't distinguish between different reads, or even know
+ * the length of the read until the read is complete, so read data a
+ * byte at a time. The device is responsible for adding the length
+ * byte on block reads. This call cannot fail, it should return
+ * something, preferably 0xff if nothing is available.
+ * This may be NULL if no data is read from the device. Reads will
+ * return 0xff in that case.
+ */
+ uint8_t (*receive_byte)(SMBusDevice *dev);
} SMBusDeviceClass;
struct SMBusDevice {
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 08/19] i2c:smbus_eeprom: Get rid of the quick command
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (6 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 07/19] i2c:smbus: Simplify read handling minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 09/19] i2c:smbus: Make white space in switch statements consistent minyard
` (10 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
It's not necessary, it won't be called if it's NULL.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
hw/i2c/smbus_eeprom.c | 8 --------
1 file changed, 8 deletions(-)
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index c2b9e3383e..4bc579e69e 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -36,13 +36,6 @@ typedef struct SMBusEEPROMDevice {
uint8_t offset;
} SMBusEEPROMDevice;
-static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read)
-{
-#ifdef DEBUG
- printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read);
-#endif
-}
-
static uint8_t eeprom_receive_byte(SMBusDevice *dev)
{
SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
@@ -95,7 +88,6 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
dc->realize = smbus_eeprom_realize;
- sc->quick_cmd = eeprom_quick_cmd;
sc->receive_byte = eeprom_receive_byte;
sc->write_data = eeprom_write_data;
dc->props = smbus_eeprom_properties;
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 09/19] i2c:smbus: Make white space in switch statements consistent
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (7 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 08/19] i2c:smbus_eeprom: Get rid of the quick command minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 10/19] boards.h: Ignore migration for SMBus devices on older machines minyard
` (9 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
It had spaces between cases in some places and not others. Add a space
for every one.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
hw/i2c/smbus_eeprom.c | 1 +
hw/i2c/smbus_slave.c | 9 +++++++++
2 files changed, 10 insertions(+)
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index 4bc579e69e..62e634c745 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -41,6 +41,7 @@ static uint8_t eeprom_receive_byte(SMBusDevice *dev)
SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
uint8_t *data = eeprom->data;
uint8_t val = data[eeprom->offset++];
+
#ifdef DEBUG
printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n",
dev->i2c.address, val);
diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c
index 52a57423ee..5b3046f6a3 100644
--- a/hw/i2c/smbus_slave.c
+++ b/hw/i2c/smbus_slave.c
@@ -70,6 +70,7 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
DPRINTF("Incoming data\n");
dev->mode = SMBUS_WRITE_DATA;
break;
+
default:
BADF("Unexpected send start condition in state %d\n", dev->mode);
dev->mode = SMBUS_CONFUSED;
@@ -83,6 +84,7 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
DPRINTF("Read mode\n");
dev->mode = SMBUS_READ_DATA;
break;
+
case SMBUS_WRITE_DATA:
if (dev->data_len == 0) {
BADF("Read after write with no data\n");
@@ -93,6 +95,7 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
dev->mode = SMBUS_READ_DATA;
}
break;
+
default:
BADF("Unexpected recv start condition in state %d\n", dev->mode);
dev->mode = SMBUS_CONFUSED;
@@ -129,9 +132,11 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
case SMBUS_DONE:
/* Nothing to do. */
break;
+
case SMBUS_READ_DATA:
dev->mode = SMBUS_DONE;
break;
+
default:
BADF("Unexpected NACK in state %d\n", dev->mode);
dev->mode = SMBUS_CONFUSED;
@@ -155,11 +160,13 @@ static uint8_t smbus_i2c_recv(I2CSlave *s)
}
DPRINTF("Read data %02x\n", ret);
break;
+
default:
BADF("Unexpected read in state %d\n", dev->mode);
dev->mode = SMBUS_CONFUSED;
break;
}
+
return ret;
}
@@ -176,10 +183,12 @@ static int smbus_i2c_send(I2CSlave *s, uint8_t data)
dev->data_buf[dev->data_len++] = data;
}
break;
+
default:
BADF("Unexpected write in state %d\n", dev->mode);
break;
}
+
return 0;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 10/19] boards.h: Ignore migration for SMBus devices on older machines
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (8 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 09/19] i2c:smbus: Make white space in switch statements consistent minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 11/19] i2c:pm_smbus: Fix pm_smbus handling of I2C block read minyard
` (8 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard, Eduardo Habkost,
Marcel Apfelbaum
From: Corey Minyard <cminyard@mvista.com>
Migration capability is being added for pm_smbus and SMBus devices.
This change will allow backwards compatibility to be kept when
migrating back to an old qemu version. Add a bool to the machine
class tho keep smbus migration from happening. Future changes
will use this.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
hw/i386/pc_piix.c | 1 +
hw/i386/pc_q35.c | 1 +
include/hw/boards.h | 1 +
3 files changed, 3 insertions(+)
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 6ba163ccbb..3bead1143f 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -442,6 +442,7 @@ static void pc_i440fx_3_1_machine_options(MachineClass *m)
{
pc_i440fx_4_0_machine_options(m);
m->is_default = 0;
+ m->smbus_no_migration_support = true;
m->alias = NULL;
compat_props_add(m->compat_props, hw_compat_3_1, hw_compat_3_1_len);
compat_props_add(m->compat_props, pc_compat_3_1, pc_compat_3_1_len);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 1689885cac..f24ee74cc5 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -378,6 +378,7 @@ static void pc_q35_3_1_machine_options(MachineClass *m)
{
pc_q35_4_0_machine_options(m);
m->default_kernel_irqchip_split = false;
+ m->smbus_no_migration_support = true;
m->alias = NULL;
compat_props_add(m->compat_props, hw_compat_3_1, hw_compat_3_1_len);
compat_props_add(m->compat_props, pc_compat_3_1, pc_compat_3_1_len);
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 02f114085f..e7f7b85008 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -207,6 +207,7 @@ struct MachineClass {
void (*numa_auto_assign_ram)(MachineClass *mc, NodeInfo *nodes,
int nb_nodes, ram_addr_t size);
bool ignore_boot_device_suffixes;
+ bool smbus_no_migration_support;
HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
DeviceState *dev);
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 11/19] i2c:pm_smbus: Fix pm_smbus handling of I2C block read
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (9 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 10/19] boards.h: Ignore migration for SMBus devices on older machines minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 12/19] migration: Add a VMSTATE_BOOL_TEST() macro minyard
` (7 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
The I2C block read function of pm_smbus was completely broken. It
required doing some direct I2C handling because it didn't have a
defined size, the OS code just reads bytes until it marks the
transaction finished.
This also required adjusting how the AMIBIOS workaround code worked,
the I2C block mode was setting STS_HOST_BUSY during a transaction,
so that bit could no longer be used to inform the host status read
code to start the transaction. Create a explicit bool for that
operation.
Also, don't read the next byte from the device in byte-by-byte
mode unless the OS is actually clearing the byte done bit. Just
assuming that's what the OS is doing is a bad idea.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
hw/i2c/pm_smbus.c | 86 ++++++++++++++++++++++++++++++---------
include/hw/i2c/pm_smbus.h | 6 +++
2 files changed, 73 insertions(+), 19 deletions(-)
diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 6cfb7eb1b3..81d2a425ec 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -118,19 +118,30 @@ static void smb_transaction(PMSMBus *s)
}
break;
case PROT_I2C_BLOCK_READ:
- if (read) {
- int xfersize = s->smb_data0;
- if (xfersize > sizeof(s->smb_data)) {
- xfersize = sizeof(s->smb_data);
- }
- ret = smbus_read_block(bus, addr, s->smb_data1, s->smb_data,
- xfersize, false, true);
- goto data8;
- } else {
- /* The manual says the behavior is undefined, just set DEV_ERR. */
+ /* According to the Linux i2c-i801 driver:
+ * NB: page 240 of ICH5 datasheet shows that the R/#W
+ * bit should be cleared here, even when reading.
+ * However if SPD Write Disable is set (Lynx Point and later),
+ * the read will fail if we don't set the R/#W bit.
+ * So at least Linux may or may not set the read bit here.
+ * So just ignore the read bit for this command.
+ */
+ if (i2c_start_transfer(bus, addr, 0)) {
goto error;
}
- break;
+ ret = i2c_send(bus, s->smb_data1);
+ if (ret) {
+ goto error;
+ }
+ if (i2c_start_transfer(bus, addr, 1)) {
+ goto error;
+ }
+ s->in_i2c_block_read = true;
+ s->smb_blkdata = i2c_recv(s->smbus);
+ s->op_done = false;
+ s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
+ goto out;
+
case PROT_BLOCK_DATA:
if (read) {
ret = smbus_read_block(bus, addr, cmd, s->smb_data,
@@ -208,6 +219,7 @@ static void smb_transaction_start(PMSMBus *s)
{
if (s->smb_ctl & CTL_INTREN) {
smb_transaction(s);
+ s->start_transaction_on_status_read = false;
} else {
/* Do not execute immediately the command; it will be
* executed when guest will read SMB_STAT register. This
@@ -217,6 +229,7 @@ static void smb_transaction_start(PMSMBus *s)
* checking for status. If STS_HOST_BUSY doesn't get
* set, it gets stuck. */
s->smb_stat |= STS_HOST_BUSY;
+ s->start_transaction_on_status_read = true;
}
}
@@ -226,19 +239,38 @@ smb_irq_value(PMSMBus *s)
return ((s->smb_stat & ~STS_HOST_BUSY) != 0) && (s->smb_ctl & CTL_INTREN);
}
+static bool
+smb_byte_by_byte(PMSMBus *s)
+{
+ if (s->op_done) {
+ return false;
+ }
+ if (s->in_i2c_block_read) {
+ return true;
+ }
+ return !(s->smb_auxctl & AUX_BLK);
+}
+
static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
unsigned width)
{
PMSMBus *s = opaque;
+ uint8_t clear_byte_done;
SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx
" val=0x%02" PRIx64 "\n", addr, val);
switch(addr) {
case SMBHSTSTS:
+ clear_byte_done = s->smb_stat & val & STS_BYTE_DONE;
s->smb_stat &= ~(val & ~STS_HOST_BUSY);
- if (!s->op_done && !(s->smb_auxctl & AUX_BLK)) {
+ if (clear_byte_done && smb_byte_by_byte(s)) {
uint8_t read = s->smb_addr & 0x01;
+ if (s->in_i2c_block_read) {
+ /* See comment below PROT_I2C_BLOCK_READ above. */
+ read = 1;
+ }
+
s->smb_index++;
if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
s->smb_index = 0;
@@ -268,12 +300,23 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
s->smb_stat |= STS_BYTE_DONE;
} else if (s->smb_ctl & CTL_LAST_BYTE) {
s->op_done = true;
- s->smb_blkdata = s->smb_data[s->smb_index];
+ if (s->in_i2c_block_read) {
+ s->in_i2c_block_read = false;
+ s->smb_blkdata = i2c_recv(s->smbus);
+ i2c_nack(s->smbus);
+ i2c_end_transfer(s->smbus);
+ } else {
+ s->smb_blkdata = s->smb_data[s->smb_index];
+ }
s->smb_index = 0;
s->smb_stat |= STS_INTR;
s->smb_stat &= ~STS_HOST_BUSY;
} else {
- s->smb_blkdata = s->smb_data[s->smb_index];
+ if (s->in_i2c_block_read) {
+ s->smb_blkdata = i2c_recv(s->smbus);
+ } else {
+ s->smb_blkdata = s->smb_data[s->smb_index];
+ }
s->smb_stat |= STS_BYTE_DONE;
}
}
@@ -284,6 +327,10 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
if (!s->op_done) {
s->smb_index = 0;
s->op_done = true;
+ if (s->in_i2c_block_read) {
+ s->in_i2c_block_read = false;
+ i2c_end_transfer(s->smbus);
+ }
}
smb_transaction_start(s);
}
@@ -337,8 +384,9 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
switch(addr) {
case SMBHSTSTS:
val = s->smb_stat;
- if (s->smb_stat & STS_HOST_BUSY) {
+ if (s->start_transaction_on_status_read) {
/* execute command now */
+ s->start_transaction_on_status_read = false;
s->smb_stat &= ~STS_HOST_BUSY;
smb_transaction(s);
}
@@ -359,10 +407,10 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
val = s->smb_data1;
break;
case SMBBLKDAT:
- if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
- s->smb_index = 0;
- }
- if (s->smb_auxctl & AUX_BLK) {
+ if (s->smb_auxctl & AUX_BLK && !s->in_i2c_block_read) {
+ if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
+ s->smb_index = 0;
+ }
val = s->smb_data[s->smb_index++];
if (!s->op_done && s->smb_index == s->smb_data0) {
s->op_done = true;
diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h
index 6dd5b7040b..7bcca97672 100644
--- a/include/hw/i2c/pm_smbus.h
+++ b/include/hw/i2c/pm_smbus.h
@@ -33,6 +33,12 @@ typedef struct PMSMBus {
/* Set on block transfers after the last byte has been read, so the
INTR bit can be set at the right time. */
bool op_done;
+
+ /* Set during an I2C block read, so we know how to handle data. */
+ bool in_i2c_block_read;
+
+ /* Used to work around a bug in AMIBIOS, see smb_transaction_start() */
+ bool start_transaction_on_status_read;
} PMSMBus;
void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk);
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 12/19] migration: Add a VMSTATE_BOOL_TEST() macro
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (10 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 11/19] i2c:pm_smbus: Fix pm_smbus handling of I2C block read minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 13/19] i2c:pm_smbus: Fix state transfer minyard
` (6 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
This will be needed by coming I2C changes.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
include/migration/vmstate.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 067b126cf1..a668ec75b8 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -851,6 +851,9 @@ extern const VMStateInfo vmstate_info_qtailq;
#define VMSTATE_INT32_POSITIVE_LE(_f, _s) \
VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
+#define VMSTATE_BOOL_TEST(_f, _s, _t) \
+ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_bool, bool)
+
#define VMSTATE_INT8_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_int8, int8_t)
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 13/19] i2c:pm_smbus: Fix state transfer
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (11 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 12/19] migration: Add a VMSTATE_BOOL_TEST() macro minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 14/19] i2c:smbus_slave: Add an SMBus vmstate structure minyard
` (5 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
Transfer the state information for the SMBus registers and
internal data so it will work on a VM transfer.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
hw/acpi/piix4.c | 7 +++++++
hw/i2c/pm_smbus.c | 31 +++++++++++++++++++++++++++++++
hw/i2c/smbus_ich9.c | 10 +++++++++-
include/hw/i2c/pm_smbus.h | 9 +++++++++
4 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 88f9a9ec09..7f8efe9997 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -302,6 +302,11 @@ static const VMStateDescription vmstate_cpuhp_state = {
}
};
+static bool piix4_vmstate_need_smbus(void *opaque, int version_id)
+{
+ return pm_smbus_vmstate_needed();
+}
+
/* qemu-kvm 1.2 uses version 3 but advertised as 2
* To support incoming qemu-kvm 1.2 migration, change version_id
* and minimum_version_id to 2 below (which breaks migration from
@@ -321,6 +326,8 @@ static const VMStateDescription vmstate_acpi = {
VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState),
VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState),
VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
+ VMSTATE_STRUCT_TEST(smb, PIIX4PMState, piix4_vmstate_need_smbus, 3,
+ pmsmb_vmstate, PMSMBus),
VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState),
VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 81d2a425ec..e48544f909 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -19,6 +19,7 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
+#include "hw/boards.h"
#include "hw/i2c/pm_smbus.h"
#include "hw/i2c/smbus_master.h"
@@ -453,6 +454,36 @@ static const MemoryRegionOps pm_smbus_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+bool pm_smbus_vmstate_needed(void)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
+
+ return !mc->smbus_no_migration_support;
+}
+
+const VMStateDescription pmsmb_vmstate = {
+ .name = "pmsmb",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(smb_stat, PMSMBus),
+ VMSTATE_UINT8(smb_ctl, PMSMBus),
+ VMSTATE_UINT8(smb_cmd, PMSMBus),
+ VMSTATE_UINT8(smb_addr, PMSMBus),
+ VMSTATE_UINT8(smb_data0, PMSMBus),
+ VMSTATE_UINT8(smb_data1, PMSMBus),
+ VMSTATE_UINT32(smb_index, PMSMBus),
+ VMSTATE_UINT8_ARRAY(smb_data, PMSMBus, PM_SMBUS_MAX_MSG_SIZE),
+ VMSTATE_UINT8(smb_auxctl, PMSMBus),
+ VMSTATE_UINT8(smb_blkdata, PMSMBus),
+ VMSTATE_BOOL(i2c_enable, PMSMBus),
+ VMSTATE_BOOL(op_done, PMSMBus),
+ VMSTATE_BOOL(in_i2c_block_read, PMSMBus),
+ VMSTATE_BOOL(start_transaction_on_status_read, PMSMBus),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk)
{
smb->op_done = true;
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index e6d8d28194..7b24be8256 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -43,12 +43,20 @@ typedef struct ICH9SMBState {
PMSMBus smb;
} ICH9SMBState;
+static bool ich9_vmstate_need_smbus(void *opaque, int version_id)
+{
+ return pm_smbus_vmstate_needed();
+}
+
static const VMStateDescription vmstate_ich9_smbus = {
.name = "ich9_smb",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState),
+ VMSTATE_PCI_DEVICE(dev, ICH9SMBState),
+ VMSTATE_BOOL_TEST(irq_enabled, ICH9SMBState, ich9_vmstate_need_smbus),
+ VMSTATE_STRUCT_TEST(smb, ICH9SMBState, ich9_vmstate_need_smbus, 1,
+ pmsmb_vmstate, PMSMBus),
VMSTATE_END_OF_LIST()
}
};
diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h
index 7bcca97672..fb55c44444 100644
--- a/include/hw/i2c/pm_smbus.h
+++ b/include/hw/i2c/pm_smbus.h
@@ -43,4 +43,13 @@ typedef struct PMSMBus {
void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk);
+/*
+ * For backwards compatibility on migration, older versions don't have
+ * working migration for pm_smbus, this lets us ignore the migrations
+ * for older machine versions.
+ */
+bool pm_smbus_vmstate_needed(void);
+
+extern const VMStateDescription pmsmb_vmstate;
+
#endif /* PM_SMBUS_H */
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 14/19] i2c:smbus_slave: Add an SMBus vmstate structure
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (12 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 13/19] i2c:pm_smbus: Fix state transfer minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 15/19] i2c:smbus_eeprom: Add normal type name and cast to smbus_eeprom.c minyard
` (4 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
There is no vmstate handling for SMBus, so no device sitting on SMBus
can have a state transfer that works reliably. So add it.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
hw/i2c/smbus_slave.c | 18 ++++++++++++++++++
include/hw/i2c/smbus_slave.h | 24 +++++++++++++++++++++---
2 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c
index 5b3046f6a3..9a2d314d1a 100644
--- a/hw/i2c/smbus_slave.c
+++ b/hw/i2c/smbus_slave.c
@@ -201,6 +201,24 @@ static void smbus_device_class_init(ObjectClass *klass, void *data)
sc->send = smbus_i2c_send;
}
+bool smbus_vmstate_needed(SMBusDevice *dev)
+{
+ return dev->mode != SMBUS_IDLE;
+}
+
+const VMStateDescription vmstate_smbus_device = {
+ .name = TYPE_SMBUS_DEVICE,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ 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_END_OF_LIST()
+ }
+};
+
static const TypeInfo smbus_device_type_info = {
.name = TYPE_SMBUS_DEVICE,
.parent = TYPE_I2C_SLAVE,
diff --git a/include/hw/i2c/smbus_slave.h b/include/hw/i2c/smbus_slave.h
index 79050fb92d..ebe068304e 100644
--- a/include/hw/i2c/smbus_slave.h
+++ b/include/hw/i2c/smbus_slave.h
@@ -69,14 +69,32 @@ typedef struct SMBusDeviceClass
uint8_t (*receive_byte)(SMBusDevice *dev);
} SMBusDeviceClass;
+#define SMBUS_DATA_MAX_LEN 34 /* command + len + 32 bytes of data. */
+
struct SMBusDevice {
/* The SMBus protocol is implemented on top of I2C. */
I2CSlave i2c;
/* Remaining fields for internal use only. */
- int mode;
- int data_len;
- uint8_t data_buf[34]; /* command + len + 32 bytes of data. */
+ int32_t mode;
+ int32_t data_len;
+ uint8_t data_buf[SMBUS_DATA_MAX_LEN];
};
+extern const VMStateDescription vmstate_smbus_device;
+
+#define VMSTATE_SMBUS_DEVICE(_field, _state) { \
+ .name = (stringify(_field)), \
+ .size = sizeof(SMBusDevice), \
+ .vmsd = &vmstate_smbus_device, \
+ .flags = VMS_STRUCT, \
+ .offset = vmstate_offset_value(_state, _field, SMBusDevice), \
+}
+
+/*
+ * Users should call this in their .needed functions to know if the
+ * SMBus slave data needs to be transferred.
+ */
+bool smbus_vmstate_needed(SMBusDevice *dev);
+
#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 15/19] i2c:smbus_eeprom: Add normal type name and cast to smbus_eeprom.c
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (13 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 14/19] i2c:smbus_slave: Add an SMBus vmstate structure minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 16/19] i2c:smbus_eeprom: Add a size constant for the smbus_eeprom size minyard
` (3 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
Create a type name and a cast macro and use those through the
code.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
hw/i2c/smbus_eeprom.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index 62e634c745..91d68ff588 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -30,6 +30,11 @@
//#define DEBUG
+#define TYPE_SMBUS_EEPROM "smbus-eeprom"
+
+#define SMBUS_EEPROM(obj) \
+ OBJECT_CHECK(SMBusEEPROMDevice, (obj), TYPE_SMBUS_EEPROM)
+
typedef struct SMBusEEPROMDevice {
SMBusDevice smbusdev;
void *data;
@@ -38,7 +43,7 @@ typedef struct SMBusEEPROMDevice {
static uint8_t eeprom_receive_byte(SMBusDevice *dev)
{
- SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+ SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev);
uint8_t *data = eeprom->data;
uint8_t val = data[eeprom->offset++];
@@ -51,7 +56,7 @@ static uint8_t eeprom_receive_byte(SMBusDevice *dev)
static int eeprom_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len)
{
- SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+ SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev);
uint8_t *data = eeprom->data;
#ifdef DEBUG
@@ -73,7 +78,7 @@ static int eeprom_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len)
static void smbus_eeprom_realize(DeviceState *dev, Error **errp)
{
- SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev;
+ SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev);
eeprom->offset = 0;
}
@@ -97,7 +102,7 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
}
static const TypeInfo smbus_eeprom_info = {
- .name = "smbus-eeprom",
+ .name = TYPE_SMBUS_EEPROM,
.parent = TYPE_SMBUS_DEVICE,
.instance_size = sizeof(SMBusEEPROMDevice),
.class_init = smbus_eeprom_class_initfn,
@@ -114,7 +119,7 @@ void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf)
{
DeviceState *dev;
- dev = qdev_create((BusState *) smbus, "smbus-eeprom");
+ dev = qdev_create((BusState *) smbus, TYPE_SMBUS_EEPROM);
qdev_prop_set_uint8(dev, "address", address);
qdev_prop_set_ptr(dev, "data", eeprom_buf);
qdev_init_nofail(dev);
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 16/19] i2c:smbus_eeprom: Add a size constant for the smbus_eeprom size
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (14 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 15/19] i2c:smbus_eeprom: Add normal type name and cast to smbus_eeprom.c minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 17/19] i2c:smbus_eeprom: Add vmstate handling to the smbus eeprom minyard
` (2 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
It was hard-coded to 256 in a number of places, create a constant
for that.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
hw/i2c/smbus_eeprom.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index 91d68ff588..b3cc9c7083 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -35,6 +35,8 @@
#define SMBUS_EEPROM(obj) \
OBJECT_CHECK(SMBusEEPROMDevice, (obj), TYPE_SMBUS_EEPROM)
+#define SMBUS_EEPROM_SIZE 256
+
typedef struct SMBusEEPROMDevice {
SMBusDevice smbusdev;
void *data;
@@ -70,7 +72,7 @@ static int eeprom_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len)
for (; len > 0; len--) {
data[eeprom->offset] = *buf++;
- eeprom->offset = (eeprom->offset + 1) % 256;
+ eeprom->offset = (eeprom->offset + 1) % SMBUS_EEPROM_SIZE;
}
return 0;
@@ -129,12 +131,14 @@ void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom,
const uint8_t *eeprom_spd, int eeprom_spd_size)
{
int i;
- uint8_t *eeprom_buf = g_malloc0(8 * 256); /* XXX: make this persistent */
+ /* XXX: make this persistent */
+ uint8_t *eeprom_buf = g_malloc0(8 * SMBUS_EEPROM_SIZE);
if (eeprom_spd_size > 0) {
memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size);
}
for (i = 0; i < nb_eeprom; i++) {
- smbus_eeprom_init_one(smbus, 0x50 + i, eeprom_buf + (i * 256));
+ smbus_eeprom_init_one(smbus, 0x50 + i,
+ eeprom_buf + (i * SMBUS_EEPROM_SIZE));
}
}
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 17/19] i2c:smbus_eeprom: Add vmstate handling to the smbus eeprom
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (15 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 16/19] i2c:smbus_eeprom: Add a size constant for the smbus_eeprom size minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 18/19] i2c:smbus_eeprom: Add a reset function to smbus_eeprom minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 19/19] i2c: Verify that the count passed in to smbus_eeprom_init() is valid minyard
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
Transfer the state of the EEPROM on a migration. This way the
data remains consistent on migration.
This required moving the actual data to a separate array and
using the data provided in the init function as a separate
initialization array, since a pointer property has to be a
void * and the array needs to be uint8_t[].
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
hw/i2c/smbus_eeprom.c | 34 ++++++++++++++++++++++++++++++++--
1 file changed, 32 insertions(+), 2 deletions(-)
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index b3cc9c7083..c0a0c4d501 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
+#include "hw/boards.h"
#include "hw/i2c/i2c.h"
#include "hw/i2c/smbus_slave.h"
#include "hw/i2c/smbus_eeprom.h"
@@ -39,8 +40,10 @@
typedef struct SMBusEEPROMDevice {
SMBusDevice smbusdev;
- void *data;
+ uint8_t data[SMBUS_EEPROM_SIZE];
+ void *init_data;
uint8_t offset;
+ bool accessed;
} SMBusEEPROMDevice;
static uint8_t eeprom_receive_byte(SMBusDevice *dev)
@@ -49,6 +52,7 @@ static uint8_t eeprom_receive_byte(SMBusDevice *dev)
uint8_t *data = eeprom->data;
uint8_t val = data[eeprom->offset++];
+ eeprom->accessed = true;
#ifdef DEBUG
printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n",
dev->i2c.address, val);
@@ -61,6 +65,7 @@ static int eeprom_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len)
SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev);
uint8_t *data = eeprom->data;
+ eeprom->accessed = true;
#ifdef DEBUG
printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
dev->i2c.address, buf[0], buf[1]);
@@ -78,15 +83,39 @@ static int eeprom_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len)
return 0;
}
+static bool smbus_eeprom_vmstate_needed(void *opaque)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
+ SMBusEEPROMDevice *eeprom = opaque;
+
+ return (eeprom->accessed || smbus_vmstate_needed(&eeprom->smbusdev)) &&
+ !mc->smbus_no_migration_support;
+}
+
+static const VMStateDescription vmstate_smbus_eeprom = {
+ .name = "smbus-eeprom",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = smbus_eeprom_vmstate_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_SMBUS_DEVICE(smbusdev, SMBusEEPROMDevice),
+ VMSTATE_UINT8_ARRAY(data, SMBusEEPROMDevice, SMBUS_EEPROM_SIZE),
+ VMSTATE_UINT8(offset, SMBusEEPROMDevice),
+ VMSTATE_BOOL(accessed, SMBusEEPROMDevice),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void smbus_eeprom_realize(DeviceState *dev, Error **errp)
{
SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev);
+ memcpy(eeprom->data, eeprom->init_data, SMBUS_EEPROM_SIZE);
eeprom->offset = 0;
}
static Property smbus_eeprom_properties[] = {
- DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
+ DEFINE_PROP_PTR("data", SMBusEEPROMDevice, init_data),
DEFINE_PROP_END_OF_LIST(),
};
@@ -99,6 +128,7 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
sc->receive_byte = eeprom_receive_byte;
sc->write_data = eeprom_write_data;
dc->props = smbus_eeprom_properties;
+ dc->vmsd = &vmstate_smbus_eeprom;
/* Reason: pointer property "data" */
dc->user_creatable = false;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 18/19] i2c:smbus_eeprom: Add a reset function to smbus_eeprom
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (16 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 17/19] i2c:smbus_eeprom: Add vmstate handling to the smbus eeprom minyard
@ 2019-02-20 13:59 ` minyard
2019-02-20 13:59 ` [Qemu-devel] [PATCH 19/19] i2c: Verify that the count passed in to smbus_eeprom_init() is valid minyard
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
Reset the contents to init data and reset the offset on a machine
reset.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
hw/i2c/smbus_eeprom.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index c0a0c4d501..44887b4a27 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -106,7 +106,17 @@ static const VMStateDescription vmstate_smbus_eeprom = {
}
};
-static void smbus_eeprom_realize(DeviceState *dev, Error **errp)
+/*
+ * Reset the EEPROM contents to the initial state on a reset. This
+ * isn't really how an EEPROM works, of course, but the general
+ * principle of QEMU is to restore function on reset to what it would
+ * be if QEMU was stopped and started.
+ *
+ * The proper thing to do would be to have a backing blockdev to hold
+ * the contents and restore that on startup, and not do this on reset.
+ * But until that time, act as if we had been stopped and restarted.
+ */
+static void smbus_eeprom_reset(DeviceState *dev)
{
SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev);
@@ -114,6 +124,11 @@ static void smbus_eeprom_realize(DeviceState *dev, Error **errp)
eeprom->offset = 0;
}
+static void smbus_eeprom_realize(DeviceState *dev, Error **errp)
+{
+ smbus_eeprom_reset(dev);
+}
+
static Property smbus_eeprom_properties[] = {
DEFINE_PROP_PTR("data", SMBusEEPROMDevice, init_data),
DEFINE_PROP_END_OF_LIST(),
@@ -125,6 +140,7 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
dc->realize = smbus_eeprom_realize;
+ dc->reset = smbus_eeprom_reset;
sc->receive_byte = eeprom_receive_byte;
sc->write_data = eeprom_write_data;
dc->props = smbus_eeprom_properties;
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 19/19] i2c: Verify that the count passed in to smbus_eeprom_init() is valid
2019-02-20 13:59 [Qemu-devel] [PATCH v5 00/19] Fix/add vmstate handling in some I2C code minyard
` (17 preceding siblings ...)
2019-02-20 13:59 ` [Qemu-devel] [PATCH 18/19] i2c:smbus_eeprom: Add a reset function to smbus_eeprom minyard
@ 2019-02-20 13:59 ` minyard
18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2019-02-20 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Dr . David Alan Gilbert, Paolo Bonzini, Michael S . Tsirkin,
Corey Minyard, Peter Maydell, Corey Minyard
From: Corey Minyard <cminyard@mvista.com>
Keep someone from passing in a bogus number
Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
hw/i2c/smbus_eeprom.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index 44887b4a27..ee392f7cb1 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -178,6 +178,8 @@ void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom,
{
int i;
/* XXX: make this persistent */
+
+ assert(nb_eeprom <= 8);
uint8_t *eeprom_buf = g_malloc0(8 * SMBUS_EEPROM_SIZE);
if (eeprom_spd_size > 0) {
memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size);
--
2.17.1
^ permalink raw reply related [flat|nested] 20+ messages in thread