[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v3 04/14] hw/i2c: support multiple masters
From: |
Peter Delevoryas |
Subject: |
[PATCH v3 04/14] hw/i2c: support multiple masters |
Date: |
Wed, 29 Jun 2022 21:51:23 -0700 |
From: Klaus Jensen <k.jensen@samsung.com>
Allow slaves to master the bus by registering a bottom halve. If the bus
is busy, the bottom half is queued up. When a slave has succesfully
mastered the bus, the bottom half is scheduled.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
[ clg : - fixed typos in commit log ]
Message-Id: <20220601210831.67259-4-its@irrelevant.dk>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
hw/i2c/core.c | 34 +++++++++++++++++++++++++++++++++-
include/hw/i2c/i2c.h | 14 ++++++++++++++
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index d0cb2d32fa..145dce6078 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -13,6 +13,7 @@
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/module.h"
+#include "qemu/main-loop.h"
#include "trace.h"
#define I2C_BROADCAST 0x00
@@ -62,6 +63,7 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name)
bus = I2C_BUS(qbus_new(TYPE_I2C_BUS, parent, name));
QLIST_INIT(&bus->current_devs);
+ QSIMPLEQ_INIT(&bus->pending_masters);
vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_i2c_bus, bus);
return bus;
}
@@ -74,7 +76,7 @@ void i2c_slave_set_address(I2CSlave *dev, uint8_t address)
/* Return nonzero if bus is busy. */
int i2c_bus_busy(I2CBus *bus)
{
- return !QLIST_EMPTY(&bus->current_devs);
+ return !QLIST_EMPTY(&bus->current_devs) || bus->bh;
}
bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast,
@@ -180,6 +182,26 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, bool
is_recv)
: I2C_START_SEND);
}
+void i2c_bus_master(I2CBus *bus, QEMUBH *bh)
+{
+ if (i2c_bus_busy(bus)) {
+ I2CPendingMaster *node = g_new(struct I2CPendingMaster, 1);
+ node->bh = bh;
+
+ QSIMPLEQ_INSERT_TAIL(&bus->pending_masters, node, entry);
+
+ return;
+ }
+
+ bus->bh = bh;
+ qemu_bh_schedule(bus->bh);
+}
+
+void i2c_bus_release(I2CBus *bus)
+{
+ bus->bh = NULL;
+}
+
int i2c_start_recv(I2CBus *bus, uint8_t address)
{
return i2c_do_start_transfer(bus, address, I2C_START_RECV);
@@ -206,6 +228,16 @@ void i2c_end_transfer(I2CBus *bus)
g_free(node);
}
bus->broadcast = false;
+
+ if (!QSIMPLEQ_EMPTY(&bus->pending_masters)) {
+ I2CPendingMaster *node = QSIMPLEQ_FIRST(&bus->pending_masters);
+ bus->bh = node->bh;
+
+ QSIMPLEQ_REMOVE_HEAD(&bus->pending_masters, entry);
+ g_free(node);
+
+ qemu_bh_schedule(bus->bh);
+ }
}
int i2c_send(I2CBus *bus, uint8_t data)
diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
index 5ca3b708c0..be8bb8b78a 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -69,13 +69,25 @@ struct I2CNode {
QLIST_ENTRY(I2CNode) next;
};
+typedef struct I2CPendingMaster I2CPendingMaster;
+
+struct I2CPendingMaster {
+ QEMUBH *bh;
+ QSIMPLEQ_ENTRY(I2CPendingMaster) entry;
+};
+
typedef QLIST_HEAD(I2CNodeList, I2CNode) I2CNodeList;
+typedef QSIMPLEQ_HEAD(I2CPendingMasters, I2CPendingMaster) I2CPendingMasters;
struct I2CBus {
BusState qbus;
I2CNodeList current_devs;
+ I2CPendingMasters pending_masters;
uint8_t saved_address;
bool broadcast;
+
+ /* Set from slave currently mastering the bus. */
+ QEMUBH *bh;
};
I2CBus *i2c_init_bus(DeviceState *parent, const char *name);
@@ -117,6 +129,8 @@ int i2c_start_send(I2CBus *bus, uint8_t address);
void i2c_end_transfer(I2CBus *bus);
void i2c_nack(I2CBus *bus);
+void i2c_bus_master(I2CBus *bus, QEMUBH *bh);
+void i2c_bus_release(I2CBus *bus);
int i2c_send(I2CBus *bus, uint8_t data);
uint8_t i2c_recv(I2CBus *bus);
bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast,
--
2.37.0
- [PATCH v3 00/14] hw/i2c/aspeed: I2C slave mode DMA RX w/ new regs, Peter Delevoryas, 2022/06/30
- [PATCH v3 01/14] hw/i2c/aspeed: Fix R_I2CD_FUN_CTRL reference, Peter Delevoryas, 2022/06/30
- [PATCH v3 02/14] hw/i2c/aspeed: Fix DMA len write-enable bit handling, Peter Delevoryas, 2022/06/30
- [PATCH v3 03/14] hw/i2c/aspeed: Fix MASTER_EN missing error message, Peter Delevoryas, 2022/06/30
- [PATCH v3 04/14] hw/i2c: support multiple masters,
Peter Delevoryas <=
- [PATCH v3 05/14] hw/i2c: add asynchronous send, Peter Delevoryas, 2022/06/30
- [PATCH v3 06/14] hw/i2c/aspeed: add slave device in old register mode, Peter Delevoryas, 2022/06/30
- [PATCH v3 07/14] hw/i2c/aspeed: Add new-registers DMA slave mode RX support, Peter Delevoryas, 2022/06/30
- [PATCH v3 08/14] hw/i2c/pmbus: Add idle state to return 0xff's, Peter Delevoryas, 2022/06/30
- [PATCH v3 09/14] hw/sensor: Add IC_DEVICE_ID to ISL voltage regulators, Peter Delevoryas, 2022/06/30
- [PATCH v3 10/14] hw/sensor: Add Renesas ISL69259 device model, Peter Delevoryas, 2022/06/30