Re: [PATCH v2 04/13] hw/i2c: support multiple masters

2022-06-29 Thread Cédric Le Goater

Corey,

On 6/29/22 05:36, Peter Delevoryas wrote:

From: Klaus Jensen 

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 
[ clg : - fixed typos in commit log ]
Message-Id: <20220601210831.67259-4-...@irrelevant.dk>
Signed-off-by: Cédric Le Goater 
---


If it is OK with you, I plan to include this I2C extension in the
next Aspeed PR.

Thanks,

C.


  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(>current_devs);
+QSIMPLEQ_INIT(>pending_masters);
  vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, _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(>current_devs);
+return !QLIST_EMPTY(>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(>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(>pending_masters)) {
+I2CPendingMaster *node = QSIMPLEQ_FIRST(>pending_masters);
+bus->bh = node->bh;
+
+QSIMPLEQ_REMOVE_HEAD(>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,





[PATCH v2 04/13] hw/i2c: support multiple masters

2022-06-28 Thread Peter Delevoryas
From: Klaus Jensen 

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 
[ clg : - fixed typos in commit log ]
Message-Id: <20220601210831.67259-4-...@irrelevant.dk>
Signed-off-by: Cédric Le Goater 
---
 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(>current_devs);
+QSIMPLEQ_INIT(>pending_masters);
 vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, _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(>current_devs);
+return !QLIST_EMPTY(>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(>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(>pending_masters)) {
+I2CPendingMaster *node = QSIMPLEQ_FIRST(>pending_masters);
+bus->bh = node->bh;
+
+QSIMPLEQ_REMOVE_HEAD(>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.30.2