Linux-i3c Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v5 0/7] Add the I3C mastership request
@ 2019-06-22 20:54 Przemyslaw Gaj
  2019-06-22 20:54 ` [PATCH v5 1/7] i3c: add addr and lvr to i2c_dev_desc structure Przemyslaw Gaj
                   ` (6 more replies)
  0 siblings, 7 replies; 21+ messages in thread
From: Przemyslaw Gaj @ 2019-06-22 20:54 UTC (permalink / raw)
  To: bbrezillon; +Cc: linux-i3c, agolec, Przemyslaw Gaj, rafalc, vitor.soares

This patch series adds support for mastership request to I3C
subsystem and Cadence I3C master driver. Mastership request
allows slave to become the master of the I3C bus.

Main changes between v4 and v5 are:
- Add populate_bus() hook
- Split i3c_master_register into init and register pair
- Split device information retrieval, let add partialy discovered devices
- Make i3c_master_set_info private
- Add separate function to register secondary master
- Reworked secondary master register in CDNS driver
- Export i3c_bus_set_mode

Main changes between v3 and v4 are:
- Reworked acquire bus ownership
- Refactored the code

Main changes between v2 and v3 are:
- Added DEFSLVS devices are registered from master driver
- Reworked I2C registering on secondary master side
- Reworked Mastership event is enabled/disabled globally (for all devices)

Main changes between initial version and v2 are:
- Reworked devices registration on secondary master side
- Reworked mastership event disabling/enabling
- Reworked bus locking during mastership takeover process
- Added DEFSLVS devices registration during initialization
- Fixed style issues

Przemyslaw Gaj (7):
  i3c: add addr and lvr to i2c_dev_desc structure
  i3c: split i3c_master_register into init - register pair
  i3c: export i3c_bus_set_mode function
  i3c: Add support for mastership request to I3C subsystem
  i3c: master: cdns: add support for mastership request to Cadence I3C
    master     driver.
  i3c: master: Add module author
  MAINTAINERS: add myself as co-maintainer of i3c subsystem

 MAINTAINERS                          |   1 +
 drivers/i3c/device.c                 |  26 ++
 drivers/i3c/internals.h              |   4 +
 drivers/i3c/master.c                 | 694 +++++++++++++++++++++++------
 drivers/i3c/master/dw-i3c-master.c   |  38 +-
 drivers/i3c/master/i3c-master-cdns.c | 837 +++++++++++++++++++++++++++--------
 include/linux/i3c/master.h           |  52 ++-
 7 files changed, 1303 insertions(+), 349 deletions(-)

-- 
2.4.5


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v5 1/7] i3c: add addr and lvr to i2c_dev_desc structure
  2019-06-22 20:54 [PATCH v5 0/7] Add the I3C mastership request Przemyslaw Gaj
@ 2019-06-22 20:54 ` Przemyslaw Gaj
  2019-06-22 20:55 ` [PATCH v5 2/7] i3c: split i3c_master_register into init - register pair Przemyslaw Gaj
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 21+ messages in thread
From: Przemyslaw Gaj @ 2019-06-22 20:54 UTC (permalink / raw)
  To: bbrezillon; +Cc: linux-i3c, agolec, Przemyslaw Gaj, rafalc, vitor.soares

I need to store address and lvr value for I2C devices without static definition
in DT. This allows secondary master to transmit DEFSLVS command properly.

Main changes between v4 and v5:
- Change in defslvs to use addr and lvr from i2c_dev_desc structure
- Change in CDNS and DW drivers to use addr and lvr from i2c_dev_desc structure

Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
---
 drivers/i3c/master.c                 | 10 ++++++----
 drivers/i3c/master/dw-i3c-master.c   |  4 ++--
 drivers/i3c/master/i3c-master-cdns.c |  4 ++--
 include/linux/i3c/master.h           |  5 +++++
 4 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 2f9a54d..0f7c31e 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -620,6 +620,8 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
 
 	dev->common.master = master;
 	dev->boardinfo = boardinfo;
+	dev->addr = boardinfo->base.addr;
+	dev->lvr = boardinfo->lvr;
 
 	return dev;
 }
@@ -939,8 +941,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master)
 
 	desc = defslvs->slaves;
 	i3c_bus_for_each_i2cdev(bus, i2cdev) {
-		desc->lvr = i2cdev->boardinfo->lvr;
-		desc->static_addr = i2cdev->boardinfo->base.addr << 1;
+		desc->lvr = i2cdev->lvr;
+		desc->static_addr = i2cdev->addr << 1;
 		desc++;
 	}
 
@@ -1607,8 +1609,8 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
 				 common.node) {
 		i3c_master_detach_i2c_dev(i2cdev);
 		i3c_bus_set_addr_slot_status(&master->bus,
-					i2cdev->boardinfo->base.addr,
-					I3C_ADDR_SLOT_FREE);
+					     i2cdev->addr,
+					     I3C_ADDR_SLOT_FREE);
 		i3c_master_free_i2c_dev(i2cdev);
 	}
 }
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 9934a12..22ac305 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -1041,12 +1041,12 @@ static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
 		return -ENOMEM;
 
 	data->index = pos;
-	master->addrs[pos] = dev->boardinfo->base.addr;
+	master->addrs[pos] = dev->addr;
 	master->free_pos &= ~BIT(pos);
 	i2c_dev_set_master_data(dev, data);
 
 	writel(DEV_ADDR_TABLE_LEGACY_I2C_DEV |
-	       DEV_ADDR_TABLE_STATIC_ADDR(dev->boardinfo->base.addr),
+	       DEV_ADDR_TABLE_STATIC_ADDR(dev->addr),
 	       master->regs +
 	       DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
 
diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
index 237f24a..5aee315 100644
--- a/drivers/i3c/master/i3c-master-cdns.c
+++ b/drivers/i3c/master/i3c-master-cdns.c
@@ -1005,9 +1005,9 @@ static int cdns_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
 	master->free_rr_slots &= ~BIT(slot);
 	i2c_dev_set_master_data(dev, data);
 
-	writel(prepare_rr0_dev_address(dev->boardinfo->base.addr),
+	writel(prepare_rr0_dev_address(dev->addr),
 	       master->regs + DEV_ID_RR0(data->id));
-	writel(dev->boardinfo->lvr, master->regs + DEV_ID_RR2(data->id));
+	writel(dev->lvr, master->regs + DEV_ID_RR2(data->id));
 	writel(readl(master->regs + DEVS_CTRL) |
 	       DEVS_CTRL_DEV_ACTIVE(data->id),
 	       master->regs + DEVS_CTRL);
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index d480ab7..42bb215 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -71,6 +71,9 @@ struct i2c_dev_boardinfo {
  * @common: common part of the I2C device descriptor
  * @boardinfo: pointer to the boardinfo attached to this I2C device
  * @dev: I2C device object registered to the I2C framework
+ * @addr: I2C device address
+ * @lvr: LVR (Legacy Virtual Register) needed by the I3C core to know about
+ *	 the I2C device limitations
  *
  * Each I2C device connected on the bus will have an i2c_dev_desc.
  * This object is created by the core and later attached to the controller
@@ -84,6 +87,8 @@ struct i2c_dev_desc {
 	struct i3c_i2c_dev_desc common;
 	const struct i2c_dev_boardinfo *boardinfo;
 	struct i2c_client *dev;
+	u16 addr;
+	u8 lvr;
 };
 
 /**
-- 
2.4.5


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v5 2/7] i3c: split i3c_master_register into init - register pair
  2019-06-22 20:54 [PATCH v5 0/7] Add the I3C mastership request Przemyslaw Gaj
  2019-06-22 20:54 ` [PATCH v5 1/7] i3c: add addr and lvr to i2c_dev_desc structure Przemyslaw Gaj
@ 2019-06-22 20:55 ` Przemyslaw Gaj
  2019-07-06  8:48   ` Boris Brezillon
  2019-12-02 10:31   ` Przemyslaw Gaj
  2019-06-22 20:55 ` [PATCH v5 3/7] i3c: export i3c_bus_set_mode function Przemyslaw Gaj
                   ` (4 subsequent siblings)
  6 siblings, 2 replies; 21+ messages in thread
From: Przemyslaw Gaj @ 2019-06-22 20:55 UTC (permalink / raw)
  To: bbrezillon; +Cc: linux-i3c, agolec, Przemyslaw Gaj, rafalc, vitor.soares

This patch is base for mastership takeover where secondary master is
initialized at probe time but register may be postponed till dynamic address is
assigned to our device.

Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
---
 drivers/i3c/master.c                 | 86 ++++++++++++++++++++----------------
 drivers/i3c/master/dw-i3c-master.c   | 34 +++++++-------
 drivers/i3c/master/i3c-master-cdns.c | 45 ++++++++++---------
 include/linux/i3c/master.h           | 12 ++---
 4 files changed, 94 insertions(+), 83 deletions(-)

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 0f7c31e..759078f 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -1528,32 +1528,9 @@ int i3c_master_do_daa(struct i3c_master_controller *master)
 }
 EXPORT_SYMBOL_GPL(i3c_master_do_daa);
 
-/**
- * i3c_master_set_info() - set master device information
- * @master: master used to send frames on the bus
- * @info: I3C device information
- *
- * Set master device info. This should be called from
- * &i3c_master_controller_ops->bus_init().
- *
- * Not all &i3c_device_info fields are meaningful for a master device.
- * Here is a list of fields that should be properly filled:
- *
- * - &i3c_device_info->dyn_addr
- * - &i3c_device_info->bcr
- * - &i3c_device_info->dcr
- * - &i3c_device_info->pid
- * - &i3c_device_info->hdr_cap if %I3C_BCR_HDR_CAP bit is set in
- *   &i3c_device_info->bcr
- *
- * This function must be called with the bus lock held in maintenance mode.
- *
- * Return: 0 if @info contains valid information (not every piece of
- * information can be checked, but we can at least make sure @info->dyn_addr
- * and @info->bcr are correct), -EINVAL otherwise.
- */
-int i3c_master_set_info(struct i3c_master_controller *master,
-			const struct i3c_device_info *info)
+static int i3c_master_set_info(struct i3c_master_controller *master,
+			       const struct i3c_device_info *info,
+			       bool secondary)
 {
 	struct i3c_dev_desc *i3cdev;
 	int ret;
@@ -1586,7 +1563,6 @@ int i3c_master_set_info(struct i3c_master_controller *master,
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(i3c_master_set_info);
 
 static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
 {
@@ -2403,7 +2379,7 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
 }
 
 /**
- * i3c_master_register() - register an I3C master
+ * i3c_master_init() - initializes all the structures required by I3C master
  * @master: master used to send frames on the bus
  * @parent: the parent device (the one that provides this I3C master
  *	    controller)
@@ -2417,16 +2393,14 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
  * - creates and initializes the I3C bus
  * - populates the bus with static I2C devs if @parent->of_node is not
  *   NULL
- * - registers all I3C devices added by the controller during bus
- *   initialization
- * - registers the I2C adapter and all I2C devices
+ * - set bus mode when registering I2C devices.
  *
  * Return: 0 in case of success, a negative error code otherwise.
  */
-int i3c_master_register(struct i3c_master_controller *master,
-			struct device *parent,
-			const struct i3c_master_controller_ops *ops,
-			bool secondary)
+int i3c_master_init(struct i3c_master_controller *master,
+		    struct device *parent,
+		    const struct i3c_master_controller_ops *ops,
+		    bool secondary)
 {
 	struct i3c_bus *i3cbus = i3c_master_get_bus(master);
 	enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
@@ -2488,10 +2462,47 @@ int i3c_master_register(struct i3c_master_controller *master,
 		ret = -ENOMEM;
 		goto err_put_dev;
 	}
+	return 0;
+
+err_put_dev:
+	put_device(&master->dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_master_init);
+
+void i3c_master_cleanup(struct i3c_master_controller *master)
+{
+	put_device(&master->dev);
+}
+EXPORT_SYMBOL_GPL(i3c_master_cleanup);
+
+/**
+ * i3c_master_register() - register an primary I3C master
+ * @master: master used to send frames on the bus
+ * @info: master info, describes this device
+ *
+ * This function takes care of everything for you:
+ *
+ * - updates this master info
+ * - registers all I3C devices added by the controller during bus
+ *   initialization
+ * - registers the I2C adapter and all I2C devices
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int i3c_master_register(struct i3c_master_controller *master,
+			struct i3c_device_info *info)
+{
+	int ret;
+
+	ret = i3c_master_set_info(master, info, master->secondary);
+	if (ret)
+		return ret;
 
 	ret = i3c_master_bus_init(master);
 	if (ret)
-		goto err_put_dev;
+		return ret;
 
 	ret = device_add(&master->dev);
 	if (ret)
@@ -2522,9 +2533,6 @@ int i3c_master_register(struct i3c_master_controller *master,
 err_cleanup_bus:
 	i3c_master_bus_cleanup(master);
 
-err_put_dev:
-	put_device(&master->dev);
-
 	return ret;
 }
 EXPORT_SYMBOL_GPL(i3c_master_register);
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 22ac305..8e91364 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -593,7 +593,6 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
 {
 	struct dw_i3c_master *master = to_dw_i3c_master(m);
 	struct i3c_bus *bus = i3c_master_get_bus(m);
-	struct i3c_device_info info = { };
 	u32 thld_ctrl;
 	int ret;
 
@@ -623,20 +622,6 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
 	writel(INTR_MASTER_MASK, master->regs + INTR_STATUS_EN);
 	writel(INTR_MASTER_MASK, master->regs + INTR_SIGNAL_EN);
 
-	ret = i3c_master_get_free_addr(m, 0);
-	if (ret < 0)
-		return ret;
-
-	writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret),
-	       master->regs + DEVICE_ADDR);
-
-	memset(&info, 0, sizeof(info));
-	info.dyn_addr = ret;
-
-	ret = i3c_master_set_info(&master->base, &info);
-	if (ret)
-		return ret;
-
 	writel(IBI_REQ_REJECT_ALL, master->regs + IBI_SIR_REQ_REJECT);
 	writel(IBI_REQ_REJECT_ALL, master->regs + IBI_MR_REQ_REJECT);
 
@@ -1109,6 +1094,7 @@ static int dw_i3c_probe(struct platform_device *pdev)
 {
 	struct dw_i3c_master *master;
 	struct resource *res;
+	struct i3c_device_info info = { };
 	int ret, irq;
 
 	master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
@@ -1160,8 +1146,22 @@ static int dw_i3c_probe(struct platform_device *pdev)
 	master->maxdevs = ret >> 16;
 	master->free_pos = GENMASK(master->maxdevs - 1, 0);
 
-	ret = i3c_master_register(&master->base, &pdev->dev,
-				  &dw_mipi_i3c_ops, false);
+	ret = i3c_master_init(&master->base, &pdev->dev,
+			      &dw_mipi_i3c_ops, false);
+	if (ret)
+		goto err_assert_rst;
+
+	ret = i3c_master_get_free_addr(&master->base, 0);
+	if (ret < 0)
+		goto err_assert_rst;
+
+	writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret),
+	       master->regs + DEVICE_ADDR);
+
+	memset(&info, 0, sizeof(info));
+	info.dyn_addr = ret;
+
+	ret = i3c_master_register(&master->base, &info);
 	if (ret)
 		goto err_assert_rst;
 
diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
index 5aee315..9706426 100644
--- a/drivers/i3c/master/i3c-master-cdns.c
+++ b/drivers/i3c/master/i3c-master-cdns.c
@@ -1193,8 +1193,7 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
 	unsigned long pres_step, sysclk_rate, max_i2cfreq;
 	struct i3c_bus *bus = i3c_master_get_bus(m);
 	u32 ctrl, prescl0, prescl1, pres, low;
-	struct i3c_device_info info = { };
-	int ret, ncycles;
+	int ncycles;
 
 	switch (bus->mode) {
 	case I3C_BUS_MODE_PURE:
@@ -1247,22 +1246,6 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
 	prescl1 = PRESCL_CTRL1_OD_LOW(ncycles);
 	writel(prescl1, master->regs + PRESCL_CTRL1);
 
-	/* Get an address for the master. */
-	ret = i3c_master_get_free_addr(m, 0);
-	if (ret < 0)
-		return ret;
-
-	writel(prepare_rr0_dev_address(ret) | DEV_ID_RR0_IS_I3C,
-	       master->regs + DEV_ID_RR0(0));
-
-	cdns_i3c_master_dev_rr_to_info(master, 0, &info);
-	if (info.bcr & I3C_BCR_HDR_CAP)
-		info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
-
-	ret = i3c_master_set_info(&master->base, &info);
-	if (ret)
-		return ret;
-
 	/*
 	 * Enable Hot-Join, and, when a Hot-Join request happens, disable all
 	 * events coming from this device.
@@ -1531,6 +1514,7 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
 {
 	struct cdns_i3c_master *master;
 	struct resource *res;
+	struct i3c_device_info info = { };
 	int ret, irq;
 	u32 val;
 
@@ -1606,13 +1590,32 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
 	writel(MST_INT_IBIR_THR, master->regs + MST_IER);
 	writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
 
-	ret = i3c_master_register(&master->base, &pdev->dev,
-				  &cdns_i3c_master_ops, false);
+	ret = i3c_master_init(&master->base, &pdev->dev, &cdns_i3c_master_ops, false);
 	if (ret)
-		goto err_disable_sysclk;
+	goto err_disable_sysclk;
+
+	/* Get an address for the master. */
+	ret = i3c_master_get_free_addr(&master->base, 0);
+	if (ret < 0)
+		return ret;
+
+	writel(prepare_rr0_dev_address(ret) | DEV_ID_RR0_IS_I3C,
+	       master->regs + DEV_ID_RR0(0));
+
+	cdns_i3c_master_dev_rr_to_info(master, 0, &info);
+	if (info.bcr & I3C_BCR_HDR_CAP)
+		info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
+
+	ret = i3c_master_register(&master->base, &info);
+
+	if (ret)
+		goto err_cleanup;
 
 	return 0;
 
+err_cleanup:
+	i3c_master_cleanup(&master->base);
+
 err_disable_sysclk:
 	clk_disable_unprepare(master->sysclk);
 
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index 42bb215..df3d769 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -530,13 +530,13 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
 				  u8 addr);
 int i3c_master_do_daa(struct i3c_master_controller *master);
 
-int i3c_master_set_info(struct i3c_master_controller *master,
-			const struct i3c_device_info *info);
-
+int i3c_master_init(struct i3c_master_controller *master,
+		    struct device *parent,
+		    const struct i3c_master_controller_ops *ops,
+		    bool secondary);
+void i3c_master_cleanup(struct i3c_master_controller *master);
 int i3c_master_register(struct i3c_master_controller *master,
-			struct device *parent,
-			const struct i3c_master_controller_ops *ops,
-			bool secondary);
+			struct i3c_device_info *info);
 int i3c_master_unregister(struct i3c_master_controller *master);
 
 /**
-- 
2.4.5


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v5 3/7] i3c: export i3c_bus_set_mode function
  2019-06-22 20:54 [PATCH v5 0/7] Add the I3C mastership request Przemyslaw Gaj
  2019-06-22 20:54 ` [PATCH v5 1/7] i3c: add addr and lvr to i2c_dev_desc structure Przemyslaw Gaj
  2019-06-22 20:55 ` [PATCH v5 2/7] i3c: split i3c_master_register into init - register pair Przemyslaw Gaj
@ 2019-06-22 20:55 ` Przemyslaw Gaj
  2019-07-06  7:39   ` Boris Brezillon
  2019-06-22 20:55 ` [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem Przemyslaw Gaj
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Przemyslaw Gaj @ 2019-06-22 20:55 UTC (permalink / raw)
  To: bbrezillon; +Cc: linux-i3c, agolec, Przemyslaw Gaj, rafalc, vitor.soares

I need to export this function to let secondary master update the bus mode.
Some newly added I2C devices may operate in slower mode.

Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
---
 drivers/i3c/master.c       | 10 ++++++++++
 include/linux/i3c/master.h |  1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 759078f..cbace14 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -566,6 +566,15 @@ static const struct device_type i3c_masterdev_type = {
 	.groups	= i3c_masterdev_groups,
 };
 
+/**
+ * i3c_bus_set_mode() - set a bus mode
+ * @i3cbus: I3C bus object
+ * @mode: new bus mode
+ *
+ * This is called at initialization time and should be called when
+ * bus mode has changed, for example when secondary master registered
+ * devices after successful masership takeover.
+ */
 int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode)
 {
 	i3cbus->mode = mode;
@@ -590,6 +599,7 @@ int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(i3c_bus_set_mode);
 
 static struct i3c_master_controller *
 i2c_adapter_to_i3c_master(struct i2c_adapter *adap)
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index df3d769..e089771 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -538,6 +538,7 @@ void i3c_master_cleanup(struct i3c_master_controller *master);
 int i3c_master_register(struct i3c_master_controller *master,
 			struct i3c_device_info *info);
 int i3c_master_unregister(struct i3c_master_controller *master);
+int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode);
 
 /**
  * i3c_dev_get_master_data() - get master private data attached to an I3C
-- 
2.4.5


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem
  2019-06-22 20:54 [PATCH v5 0/7] Add the I3C mastership request Przemyslaw Gaj
                   ` (2 preceding siblings ...)
  2019-06-22 20:55 ` [PATCH v5 3/7] i3c: export i3c_bus_set_mode function Przemyslaw Gaj
@ 2019-06-22 20:55 ` Przemyslaw Gaj
  2019-07-06  9:00   ` Boris Brezillon
  2019-07-10 18:04   ` Vitor Soares
  2019-06-22 20:55 ` [PATCH v5 5/7] i3c: master: cdns: add support for mastership request to Cadence I3C master driver Przemyslaw Gaj
                   ` (2 subsequent siblings)
  6 siblings, 2 replies; 21+ messages in thread
From: Przemyslaw Gaj @ 2019-06-22 20:55 UTC (permalink / raw)
  To: bbrezillon; +Cc: linux-i3c, agolec, Przemyslaw Gaj, rafalc, vitor.soares

This patch adds support for mastership request to I3C subsystem.

Mastership event is enabled globally.

Mastership is requested automatically when device driver
tries to transfer data using master controller in slave mode.

There is still some limitation:
- I2C devices are registered on secondary master side if boardinfo
entry matching the info transmitted through the DEFSLVS frame.

Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>

---

Main changes between v4 and v5:
- Add function to test if master owns the bus
- Add i3c_secondary_master_register() function
- Add populate_bus() hook to populate the bus after mastership takeover
- Rework device information retrieval to allow adding partialy discovered
devices

Main changes between v3 and v4:
- Add i3c_master_acquire_bus_ownership to acquire the bus
- Refactored the code

Main changes between v2 and v3:
- Add i3c_bus_downgrade_maintenance_lock() for downgrading the bus
lock from maintenance to normal use
- Add additional fields to i2c_dev_desc for DEFSLVS purpose (addr, lvr)
- Add i3c_master_register_new_i2c_devs() function to register I2C devices
- Reworked I2C devices registration on secondary master side

Changes in v2:
- Add mastership disable event hook
- Changed name of mastership enable event hook
- Add function to test if master owns the bus
- Removed op_mode
- Changed parameter of i3c_master_get_accmst_locked, no need to
pass full i3c_device_info
- Changed name of mastership enable event hook
- Add function to test if master owns the bus
- Removed op_mode
- Changed parameter of i3c_master_get_accmst_locked, no need to
pass full i3c_device_info
- Removed redundant DEFSLVS command before GETACCMST
- Add i3c_master_bus_takeover function. There is a need to lock
the bus before adding devices and no matter of the controller
devices have to be added after mastership takeover.
- Add device registration during initialization on secondary master
side. Devices received by DEFSLVS (if occured). If not, device
initialization is deffered untill next mastership request.
---
 drivers/i3c/device.c       |  26 ++
 drivers/i3c/internals.h    |   4 +
 drivers/i3c/master.c       | 588 ++++++++++++++++++++++++++++++++++++++-------
 include/linux/i3c/master.h |  34 ++-
 4 files changed, 563 insertions(+), 89 deletions(-)

diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
index 69cc040..b60f637 100644
--- a/drivers/i3c/device.c
+++ b/drivers/i3c/device.c
@@ -43,7 +43,13 @@ int i3c_device_do_priv_xfers(struct i3c_device *dev,
 	}
 
 	i3c_bus_normaluse_lock(dev->bus);
+	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
+	if (ret)
+		goto err_unlock_bus;
+
 	ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
+
+err_unlock_bus:
 	i3c_bus_normaluse_unlock(dev->bus);
 
 	return ret;
@@ -114,11 +120,17 @@ int i3c_device_enable_ibi(struct i3c_device *dev)
 	int ret = -ENOENT;
 
 	i3c_bus_normaluse_lock(dev->bus);
+	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
+	if (ret)
+		goto err_unlock_bus;
+
 	if (dev->desc) {
 		mutex_lock(&dev->desc->ibi_lock);
 		ret = i3c_dev_enable_ibi_locked(dev->desc);
 		mutex_unlock(&dev->desc->ibi_lock);
 	}
+
+err_unlock_bus:
 	i3c_bus_normaluse_unlock(dev->bus);
 
 	return ret;
@@ -145,11 +157,17 @@ int i3c_device_request_ibi(struct i3c_device *dev,
 		return -EINVAL;
 
 	i3c_bus_normaluse_lock(dev->bus);
+	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
+	if (ret)
+		goto err_unlock_bus;
+
 	if (dev->desc) {
 		mutex_lock(&dev->desc->ibi_lock);
 		ret = i3c_dev_request_ibi_locked(dev->desc, req);
 		mutex_unlock(&dev->desc->ibi_lock);
 	}
+
+err_unlock_bus:
 	i3c_bus_normaluse_unlock(dev->bus);
 
 	return ret;
@@ -166,12 +184,20 @@ EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
  */
 void i3c_device_free_ibi(struct i3c_device *dev)
 {
+	int ret;
+
 	i3c_bus_normaluse_lock(dev->bus);
+	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
+	if (ret)
+		goto err_unlock_bus;
+
 	if (dev->desc) {
 		mutex_lock(&dev->desc->ibi_lock);
 		i3c_dev_free_ibi_locked(dev->desc);
 		mutex_unlock(&dev->desc->ibi_lock);
 	}
+
+err_unlock_bus:
 	i3c_bus_normaluse_unlock(dev->bus);
 }
 EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
index 86b7b44..cdfc5bf 100644
--- a/drivers/i3c/internals.h
+++ b/drivers/i3c/internals.h
@@ -14,6 +14,10 @@ extern struct bus_type i3c_bus_type;
 
 void i3c_bus_normaluse_lock(struct i3c_bus *bus);
 void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
+void i3c_bus_maintenance_lock(struct i3c_bus *bus);
+void i3c_bus_maintenance_unlock(struct i3c_bus *bus);
+int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master);
+
 
 int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
 				 struct i3c_priv_xfer *xfers,
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index cbace14..3b44e66 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -93,6 +93,18 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
 	up_read(&bus->lock);
 }
 
+/*
+ * i3c_bus_downgrade_maintenance_lock - Downgrade the bus lock to normal
+ * operation
+ *
+ * Should be called when a maintenance operation is done and normal
+ * operation is planned. See i3c_bus_maintenance_lock() and
+ * i3c_bus_normaluse_lock() for more details.
+ */
+static void i3c_bus_downgrade_maintenance_lock(struct i3c_bus *bus)
+{
+	downgrade_write(&bus->lock);
+}
 static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
 {
 	return container_of(dev, struct i3c_master_controller, dev);
@@ -341,6 +353,22 @@ static int i3c_device_probe(struct device *dev)
 	return driver->probe(i3cdev);
 }
 
+static int
+i3c_master_enable_mr_events_locked(struct i3c_master_controller *master)
+{
+	if (!master->ops->enable_mr_events)
+		return -ENOTSUPP;
+
+	return master->ops->enable_mr_events(master);
+}
+
+static void i3c_master_disable_mr_events(struct i3c_master_controller *master)
+{
+	if (!master->ops->disable_mr_events)
+		return;
+
+	master->ops->disable_mr_events(master);
+}
 static int i3c_device_remove(struct device *dev)
 {
 	struct i3c_device *i3cdev = dev_to_i3cdev(dev);
@@ -462,6 +490,42 @@ static int i3c_bus_init(struct i3c_bus *i3cbus)
 	return 0;
 }
 
+static int
+i3c_master_request_mastership_locked(struct i3c_master_controller *master)
+{
+	if (WARN_ON(master->init_done &&
+	    !rwsem_is_locked(&master->bus.lock)))
+		return -EINVAL;
+
+	if (!master->ops->request_mastership)
+		return -ENOTSUPP;
+
+	return master->ops->request_mastership(master);
+}
+
+static int i3c_master_owns_bus(struct i3c_master_controller *master)
+{
+	return (master->bus.cur_master == master->this);
+}
+
+int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master)
+{
+	int ret;
+
+	if (!i3c_master_owns_bus(master)) {
+		i3c_bus_normaluse_unlock(&master->bus);
+		i3c_bus_maintenance_lock(&master->bus);
+
+		ret = i3c_master_request_mastership_locked(master);
+		if (ret) {
+			i3c_bus_maintenance_unlock(&master->bus);
+			return ret;
+		}
+		i3c_bus_downgrade_maintenance_lock(&master->bus);
+	}
+
+	return 0;
+}
 static const char * const i3c_bus_mode_strings[] = {
 	[I3C_BUS_MODE_PURE] = "pure",
 	[I3C_BUS_MODE_MIXED_FAST] = "mixed-fast",
@@ -636,6 +700,22 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
 	return dev;
 }
 
+static struct i2c_dev_desc *
+i3c_master_alloc_i2c_dev_no_boardinfo(struct i3c_master_controller *master,
+				      u16 addr, u8 lvr)
+{
+	struct i2c_dev_desc *dev;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
+
+	dev->common.master = master;
+	dev->addr = addr;
+	dev->lvr = lvr;
+
+	return dev;
+}
 static void *i3c_ccc_cmd_dest_init(struct i3c_ccc_cmd_dest *dest, u8 addr,
 				   u16 payloadlen)
 {
@@ -705,6 +785,8 @@ i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master,
 	struct i2c_dev_desc *dev;
 
 	i3c_bus_for_each_i2cdev(&master->bus, dev) {
+		if (!dev->boardinfo)
+			continue;
 		if (dev->boardinfo->base.addr == addr)
 			return dev;
 	}
@@ -1478,7 +1560,8 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
 		return;
 
 	i3c_bus_for_each_i3cdev(&master->bus, desc) {
-		if (desc->dev || !desc->info.dyn_addr || desc == master->this)
+		if (desc->dev || !desc->info.dyn_addr ||
+		    desc == master->this || !desc->info.pid)
 			continue;
 
 		desc->dev = kzalloc(sizeof(*desc->dev), GFP_KERNEL);
@@ -1504,6 +1587,69 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
 	}
 }
 
+static struct i2c_dev_boardinfo *
+i3c_master_find_i2c_boardinfo(const struct i3c_master_controller *master,
+			      u16 addr, u8 lvr)
+{
+	struct i2c_dev_boardinfo *i2cboardinfo;
+
+	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
+		if (i2cboardinfo->base.addr == addr &&
+		    i2cboardinfo->lvr == lvr)
+			return i2cboardinfo;
+	}
+
+	return NULL;
+}
+
+static void
+i3c_master_register_new_i2c_devs(struct i3c_master_controller *master)
+{
+	struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
+	struct i2c_dev_desc *i2cdev;
+
+	if (!master->init_done)
+		return;
+
+	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
+
+		if (i2cdev->dev)
+			continue;
+
+		if (!i2cdev->boardinfo)
+			continue;
+
+		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
+	}
+}
+
+static int i3c_master_get_accmst_locked(struct i3c_master_controller *master,
+					u8 addr)
+{
+	struct i3c_ccc_getaccmst *accmst;
+	struct i3c_ccc_cmd_dest dest;
+	struct i3c_ccc_cmd cmd;
+	int ret;
+
+	accmst = i3c_ccc_cmd_dest_init(&dest, addr, sizeof(*accmst));
+	if (!accmst)
+		return -ENOMEM;
+
+	i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETACCMST, &dest, 1);
+
+	ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+	if (ret)
+		goto out;
+
+	if (dest.payload.len != sizeof(*accmst))
+		ret = -EIO;
+
+out:
+	i3c_ccc_cmd_dest_cleanup(&dest);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_master_get_accmst_locked);
 /**
  * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
  * @master: master doing the DAA
@@ -1548,10 +1694,6 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
 	if (!i3c_bus_dev_addr_is_avail(&master->bus, info->dyn_addr))
 		return -EINVAL;
 
-	if (I3C_BCR_DEVICE_ROLE(info->bcr) == I3C_BCR_I3C_MASTER &&
-	    master->secondary)
-		return -EINVAL;
-
 	if (master->this)
 		return -EINVAL;
 
@@ -1560,7 +1702,8 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
 		return PTR_ERR(i3cdev);
 
 	master->this = i3cdev;
-	master->bus.cur_master = master->this;
+	if (!secondary)
+		master->bus.cur_master = master->this;
 
 	ret = i3c_master_attach_i3c_dev(master, i3cdev);
 	if (ret)
@@ -1601,37 +1744,7 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
 	}
 }
 
-/**
- * i3c_master_bus_init() - initialize an I3C bus
- * @master: main master initializing the bus
- *
- * This function is following all initialisation steps described in the I3C
- * specification:
- *
- * 1. Attach I2C and statically defined I3C devs to the master so that the
- *    master can fill its internal device table appropriately
- *
- * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
- *    the master controller. That's usually where the bus mode is selected
- *    (pure bus or mixed fast/slow bus)
- *
- * 3. Instruct all devices on the bus to drop their dynamic address. This is
- *    particularly important when the bus was previously configured by someone
- *    else (for example the bootloader)
- *
- * 4. Disable all slave events.
- *
- * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
- *    devices that have a static address
- *
- * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
- *    remaining I3C devices
- *
- * Once this is done, all I3C and I2C devices should be usable.
- *
- * Return: a 0 in case of success, an negative error code otherwise.
- */
-static int i3c_master_bus_init(struct i3c_master_controller *master)
+static int i3c_master_attach_static_devs(struct i3c_master_controller *master)
 {
 	enum i3c_addr_slot_status status;
 	struct i2c_dev_boardinfo *i2cboardinfo;
@@ -1640,32 +1753,24 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
 	struct i2c_dev_desc *i2cdev;
 	int ret;
 
-	/*
-	 * First attach all devices with static definitions provided by the
-	 * FW.
-	 */
 	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
 		status = i3c_bus_get_addr_slot_status(&master->bus,
 						      i2cboardinfo->base.addr);
-		if (status != I3C_ADDR_SLOT_FREE) {
-			ret = -EBUSY;
-			goto err_detach_devs;
-		}
+		if (status != I3C_ADDR_SLOT_FREE)
+			return -EBUSY;
 
 		i3c_bus_set_addr_slot_status(&master->bus,
 					     i2cboardinfo->base.addr,
 					     I3C_ADDR_SLOT_I2C_DEV);
 
 		i2cdev = i3c_master_alloc_i2c_dev(master, i2cboardinfo);
-		if (IS_ERR(i2cdev)) {
-			ret = PTR_ERR(i2cdev);
-			goto err_detach_devs;
-		}
+		if (IS_ERR(i2cdev))
+			return PTR_ERR(i2cdev);
 
 		ret = i3c_master_attach_i2c_dev(master, i2cdev);
 		if (ret) {
 			i3c_master_free_i2c_dev(i2cdev);
-			goto err_detach_devs;
+			return ret;
 		}
 	}
 	list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) {
@@ -1676,27 +1781,68 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
 		if (i3cboardinfo->init_dyn_addr) {
 			status = i3c_bus_get_addr_slot_status(&master->bus,
 						i3cboardinfo->init_dyn_addr);
-			if (status != I3C_ADDR_SLOT_FREE) {
-				ret = -EBUSY;
-				goto err_detach_devs;
-			}
+			if (status != I3C_ADDR_SLOT_FREE)
+				return -EBUSY;
 		}
 
 		i3cdev = i3c_master_alloc_i3c_dev(master, &info);
-		if (IS_ERR(i3cdev)) {
-			ret = PTR_ERR(i3cdev);
-			goto err_detach_devs;
-		}
+		if (IS_ERR(i3cdev))
+			return PTR_ERR(i3cdev);
 
 		i3cdev->boardinfo = i3cboardinfo;
 
 		ret = i3c_master_attach_i3c_dev(master, i3cdev);
 		if (ret) {
 			i3c_master_free_i3c_dev(i3cdev);
-			goto err_detach_devs;
+			return ret;
 		}
 	}
 
+	return 0;
+}
+
+/**
+ * i3c_master_bus_init() - initialize an I3C bus
+ * @master: main master initializing the bus
+ *
+ * This function is following all initialisation steps described in the I3C
+ * specification:
+ *
+ * 1. Attach I2C and statically defined I3C devs to the master so that the
+ *    master can fill its internal device table appropriately
+ *
+ * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
+ *    the master controller. That's usually where the bus mode is selected
+ *    (pure bus or mixed fast/slow bus)
+ *
+ * 3. Instruct all devices on the bus to drop their dynamic address. This is
+ *    particularly important when the bus was previously configured by someone
+ *    else (for example the bootloader)
+ *
+ * 4. Disable all slave events.
+ *
+ * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
+ *    devices that have a static address
+ *
+ * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
+ *    remaining I3C devices
+ *
+ * Once this is done, all I3C and I2C devices should be usable.
+ *
+ * Return: a 0 in case of success, an negative error code otherwise.
+ */
+static int i3c_master_bus_init(struct i3c_master_controller *master)
+{
+	struct i3c_dev_desc *i3cdev;
+	int ret;
+
+	/*
+	 * First attach all devices with static definitions provided by the
+	 * FW.
+	 */
+	ret = i3c_master_attach_static_devs(master);
+	if (ret)
+		goto err_detach_devs;
 	/*
 	 * Now execute the controller specific ->bus_init() routine, which
 	 * might configure its internal logic to match the bus limitations.
@@ -1780,45 +1926,76 @@ i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev)
 }
 
 /**
- * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
- * @master: master used to send frames on the bus
- * @addr: I3C slave dynamic address assigned to the device
+ * i3c_master_add_i2c_dev_locked() - add an I2C slave to the bus
+ * @master: master used to register I2C device
+ * @addr: I2C device address
+ * @lvr: legacy virtual register value
  *
- * This function is instantiating an I3C device object and adding it to the
- * I3C device list. All device information are automatically retrieved using
- * standard CCC commands.
- *
- * The I3C device object is returned in case the master wants to attach
- * private data to it using i3c_dev_set_master_data().
+ * This function is instantiating an I2C device object and adding it to the
+ * I2C device list.
  *
  * This function must be called with the bus lock held in write mode.
  *
  * Return: a 0 in case of success, an negative error code otherwise.
  */
-int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
-				  u8 addr)
+int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
+				  u16 addr, u8 lvr)
 {
-	struct i3c_device_info info = { .dyn_addr = addr };
-	struct i3c_dev_desc *newdev, *olddev;
-	u8 old_dyn_addr = addr, expected_dyn_addr;
-	struct i3c_ibi_setup ibireq = { };
-	bool enable_ibi = false;
+	enum i3c_addr_slot_status status;
+	struct i2c_dev_desc *i2cdev;
 	int ret;
 
 	if (!master)
 		return -EINVAL;
 
-	newdev = i3c_master_alloc_i3c_dev(master, &info);
-	if (IS_ERR(newdev))
-		return PTR_ERR(newdev);
+	status = i3c_bus_get_addr_slot_status(&master->bus,
+					      addr);
+	if (status != I3C_ADDR_SLOT_FREE)
+		return -EBUSY;
 
-	ret = i3c_master_attach_i3c_dev(master, newdev);
-	if (ret)
+	i3c_bus_set_addr_slot_status(&master->bus, addr,
+				     I3C_ADDR_SLOT_I2C_DEV);
+
+	i2cdev = i3c_master_alloc_i2c_dev_no_boardinfo(master, addr, lvr);
+
+	if (IS_ERR(i2cdev)) {
+		ret = PTR_ERR(i2cdev);
+		goto err_free_dev;
+	}
+
+	i2cdev->boardinfo = i3c_master_find_i2c_boardinfo(master, addr, lvr);
+
+	ret = i3c_master_attach_i2c_dev(master, i2cdev);
+
+	if (ret) {
+		ret = PTR_ERR(i2cdev);
 		goto err_free_dev;
+	}
+
+	return 0;
+
+err_free_dev:
+	i3c_bus_set_addr_slot_status(&master->bus, addr,
+				     I3C_ADDR_SLOT_FREE);
+	i3c_master_free_i2c_dev(i2cdev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_master_add_i2c_dev_locked);
+
+static int
+i3c_master_retrieve_info_and_reuse(struct i3c_master_controller *master,
+				   struct i3c_dev_desc *newdev)
+{
+	struct i3c_dev_desc *olddev;
+	u8 old_dyn_addr = newdev->info.dyn_addr, expected_dyn_addr;
+	struct i3c_ibi_setup ibireq = { };
+	bool enable_ibi = false;
+	int ret;
 
 	ret = i3c_master_retrieve_dev_info(newdev);
 	if (ret)
-		goto err_detach_dev;
+		return ret;
 
 	olddev = i3c_master_search_i3c_dev_duplicate(newdev);
 	if (olddev) {
@@ -1857,7 +2034,7 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
 
 	ret = i3c_master_reattach_i3c_dev(newdev, old_dyn_addr);
 	if (ret)
-		goto err_detach_dev;
+		return ret;
 
 	/*
 	 * Depending on our previous state, the expected dynamic address might
@@ -1920,6 +2097,50 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
 	}
 
 	return 0;
+}
+
+/**
+ * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
+ * @master: master used to send frames on the bus
+ * @addr: I3C slave dynamic address assigned to the device
+ *
+ * This function is instantiating an I3C device object and adding it to the
+ * I3C device list. All device information are automatically retrieved using
+ * standard CCC commands.
+ *
+ * The I3C device object is returned in case the master wants to attach
+ * private data to it using i3c_dev_set_master_data().
+ *
+ * This function must be called with the bus lock held in write mode.
+ *
+ * Return: a 0 in case of success, an negative error code otherwise.
+ */
+int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
+				  u8 addr)
+{
+	struct i3c_device_info info = { .dyn_addr = addr };
+	struct i3c_dev_desc *newdev;
+	int ret;
+
+	if (!master)
+		return -EINVAL;
+
+	newdev = i3c_master_alloc_i3c_dev(master, &info);
+	if (IS_ERR(newdev))
+		return PTR_ERR(newdev);
+
+	ret = i3c_master_attach_i3c_dev(master, newdev);
+	if (ret)
+		goto err_free_dev;
+
+	if (i3c_master_owns_bus(master)) {
+		ret = i3c_master_retrieve_info_and_reuse(master, newdev);
+		if (ret)
+			goto err_detach_dev;
+	} else
+		master->want_to_acquire_bus = true;
+
+	return 0;
 
 err_detach_dev:
 	if (newdev->dev && newdev->dev->desc)
@@ -2101,11 +2322,15 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
 	}
 
 	i3c_bus_normaluse_lock(&master->bus);
+	ret = i3c_master_acquire_bus_ownership(master);
+	if (ret)
+		goto err_unlock_bus;
 	dev = i3c_master_find_i2c_dev_by_addr(master, addr);
 	if (!dev)
 		ret = -ENOENT;
 	else
 		ret = master->ops->i2c_xfers(dev, xfers, nxfers);
+err_unlock_bus:
 	i3c_bus_normaluse_unlock(&master->bus);
 
 	return ret ? ret : nxfers;
@@ -2144,9 +2369,12 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
 	 * We silently ignore failures here. The bus should keep working
 	 * correctly even if one or more i2c devices are not registered.
 	 */
-	i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
+	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
+		if (!i2cdev->boardinfo)
+			continue;
 		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
 
+	}
 	return 0;
 }
 
@@ -2385,9 +2613,76 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
 	     !ops->recycle_ibi_slot))
 		return -EINVAL;
 
+	/*
+	 * If mastership request is supported, we also need hooks to control
+	 * when mastership request can occur by enabling/disabling the event.
+	 */
+	if (ops->request_mastership &&
+	    (!ops->enable_mr_events || !ops->disable_mr_events))
+		return -EINVAL;
 	return 0;
 }
 
+static void i3c_master_register_new_devs(struct i3c_master_controller *master)
+{
+	/*
+	 * We can register devices received from master by DEFSLVS.
+	 */
+	i3c_bus_normaluse_lock(&master->bus);
+	i3c_master_register_new_i3c_devs(master);
+	i3c_master_register_new_i2c_devs(master);
+	i3c_bus_normaluse_unlock(&master->bus);
+}
+
+/**
+ * i3c_master_bus_takeover() - register new I3C devices on bus takeover
+ * @master: master used to send frames on the bus
+ *
+ * This function is useful when devices were not added
+ * during initialization or when new device joined the bus
+ * which wasn't under our control.
+ */
+void i3c_master_bus_takeover(struct i3c_master_controller *master)
+{
+	struct i3c_dev_desc *i3cdev, *i3ctmp;
+	int ret;
+
+	master->want_to_acquire_bus = false;
+
+	if (!master->init_done)
+		return;
+
+	i3c_bus_maintenance_lock(&master->bus);
+	master->ops->populate_bus(master);
+
+	list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c,
+				 common.node) {
+		if (i3cdev->info.pid)
+			continue;
+
+		ret = i3c_master_retrieve_info_and_reuse(master, i3cdev);
+		if (ret) {
+			if (i3cdev->dev && i3cdev->dev->desc)
+				i3cdev->dev->desc = NULL;
+
+			i3c_master_detach_i3c_dev(i3cdev);
+		}
+	}
+
+	/*
+	 * If current master finished bus initialization properly, we can
+	 * enable Mastership event.
+	 */
+	ret = i3c_master_enable_mr_events_locked(master);
+	if (ret)
+		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
+
+	i3c_bus_maintenance_unlock(&master->bus);
+
+	i3c_master_register_new_devs(master);
+}
+EXPORT_SYMBOL_GPL(i3c_master_bus_takeover);
+
 /**
  * i3c_master_init() - initializes all the structures required by I3C master
  * @master: master used to send frames on the bus
@@ -2417,9 +2712,6 @@ int i3c_master_init(struct i3c_master_controller *master,
 	struct i2c_dev_boardinfo *i2cbi;
 	int ret;
 
-	/* We do not support secondary masters yet. */
-	if (secondary)
-		return -ENOTSUPP;
 
 	ret = i3c_master_check_ops(ops);
 	if (ret)
@@ -2432,6 +2724,7 @@ int i3c_master_init(struct i3c_master_controller *master,
 	master->dev.release = i3c_masterdev_release;
 	master->ops = ops;
 	master->secondary = secondary;
+	master->want_to_acquire_bus = secondary;
 	INIT_LIST_HEAD(&master->boardinfo.i2c);
 	INIT_LIST_HEAD(&master->boardinfo.i3c);
 
@@ -2488,6 +2781,92 @@ void i3c_master_cleanup(struct i3c_master_controller *master)
 EXPORT_SYMBOL_GPL(i3c_master_cleanup);
 
 /**
+ * i3c_secondary_master_register() - register an secondary I3C master
+ * @master: master used to send frames on the bus
+ * @info: master info, describes this device
+ *
+ * This function takes care of everything for you:
+ *
+ * - updates this master info
+ * - registers the I2C adapter
+ * - if possible, populates the bus with devices received by DEFSLVS
+ *   command
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int i3c_secondary_master_register(struct i3c_master_controller *master,
+				  struct i3c_device_info *info)
+{
+	int ret;
+
+	ret = i3c_master_set_info(master, info, master->secondary);
+	if (ret)
+		return ret;
+
+	ret = master->ops->bus_init(master);
+	if (ret)
+		return ret;
+
+	ret = device_add(&master->dev);
+	if (ret)
+		return -1;
+
+	/*
+	 * Expose our I3C bus as an I2C adapter so that I2C devices are exposed
+	 * through the I2C subsystem.
+	 */
+	ret = i3c_master_i2c_adapter_init(master);
+	if (ret)
+		goto err_del_dev;
+
+	i3c_bus_maintenance_lock(&master->bus);
+	/*
+	 * If possible, request mastership and try to populate the bus.
+	 */
+	ret = i3c_master_request_mastership_locked(master);
+	if (ret)
+		dev_warn(&master->dev,
+			 "Mastership failed at init time (ret = %i)", ret);
+
+	/*
+	 * No matter if mastership takeover passed or not, add partialy
+	 * discovered devices. We can register them when ENEC(MR) is enabled.
+	 */
+	master->ops->populate_bus(master);
+
+	i3c_bus_maintenance_unlock(&master->bus);
+
+	/*
+	 * We're done initializing the bus and the controller, we can now
+	 * register I3C devices obtained by DEFSLVS.
+	 */
+	master->init_done = true;
+	i3c_master_register_new_devs(master);
+
+	/*
+	 * If we are owning the bus, enable ENEC(MR) to let other masters
+	 * initialize their bus.
+	 */
+	if (i3c_master_owns_bus(master)) {
+		i3c_bus_maintenance_lock(&master->bus);
+		ret = i3c_master_enable_mr_events_locked(master);
+		i3c_bus_maintenance_unlock(&master->bus);
+		if (ret)
+			dev_warn(&master->dev,
+				 "ENEC(MR) failed (ret = %i)", ret);
+	}
+
+
+	return 0;
+
+err_del_dev:
+	device_del(&master->dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_secondary_master_register);
+
+/**
  * i3c_master_register() - register an primary I3C master
  * @master: master used to send frames on the bus
  * @info: master info, describes this device
@@ -2509,7 +2888,6 @@ int i3c_master_register(struct i3c_master_controller *master,
 	ret = i3c_master_set_info(master, info, master->secondary);
 	if (ret)
 		return ret;
-
 	ret = i3c_master_bus_init(master);
 	if (ret)
 		return ret;
@@ -2535,6 +2913,16 @@ int i3c_master_register(struct i3c_master_controller *master,
 	i3c_master_register_new_i3c_devs(master);
 	i3c_bus_normaluse_unlock(&master->bus);
 
+	/*
+	 * Enable ENEC(MR) and let other masters request mastership
+	 * and initialize their bus.
+	 */
+	i3c_bus_maintenance_lock(&master->bus);
+	ret = i3c_master_enable_mr_events_locked(master);
+	i3c_bus_maintenance_unlock(&master->bus);
+	if (ret)
+		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
+
 	return 0;
 
 err_del_dev:
@@ -2548,6 +2936,29 @@ int i3c_master_register(struct i3c_master_controller *master,
 EXPORT_SYMBOL_GPL(i3c_master_register);
 
 /**
+ * i3c_master_mastership_ack() - acknowledges bus takeover.
+ * @master: master used to send frames on the bus
+ * @addr: I3C device address
+ *
+ * This function acknowledges bus takeover.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int i3c_master_mastership_ack(struct i3c_master_controller *master,
+			      u8 addr)
+{
+	int ret;
+
+	i3c_bus_maintenance_lock(&master->bus);
+	ret = i3c_master_get_accmst_locked(master, addr);
+	i3c_bus_maintenance_unlock(&master->bus);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_master_mastership_ack);
+
+
+/**
  * i3c_master_unregister() - unregister an I3C master
  * @master: master used to send frames on the bus
  *
@@ -2557,6 +2968,9 @@ EXPORT_SYMBOL_GPL(i3c_master_register);
  */
 int i3c_master_unregister(struct i3c_master_controller *master)
 {
+	i3c_bus_maintenance_lock(&master->bus);
+	i3c_master_disable_mr_events(master);
+	i3c_bus_maintenance_unlock(&master->bus);
 	i3c_master_i2c_adapter_cleanup(master);
 	i3c_master_unregister_i3c_devs(master);
 	i3c_master_bus_cleanup(master);
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index e089771..6ac9b46 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -421,6 +421,26 @@ struct i3c_bus {
  *		      for a future IBI
  *		      This method is mandatory only if ->request_ibi is not
  *		      NULL.
+ * @request_mastership: requests bus mastership. Mastership is requested
+ *                      automatically when device driver wants to transfer
+ *                      data using a master that does not currently
+ *                      owns the bus.
+ * @enable_mr_events: enable the Mastership event. Master driver can prepare
+ *                    its internal state to be ready for incoming mastership
+ *                    requests and then should send ENEC(MR) command to let
+ *                    other masters take control over the bus.
+ * @disable_mr_events: disable the Mastership event. Master driver should
+ *                     immediately send DISEC(MR) command and can perform other
+ *                     operations. For example, recycle IBI slot if used before
+ *                     for MR event.
+ * @populate_pus: populates the bus. Called after bus takeover. Secondary
+ *                master can't perform DAA procedure. This function allows to
+ *                update devices received from previous bus owner in DEFSLVS
+ *                command. Useful also when new device joins the bus controlled
+ *                by secondary master, main master will be able to add
+ *                this device after mastership takeover. Driver should also
+ *		  update bus mode when I2C device is on the bus.
+ *
  */
 struct i3c_master_controller_ops {
 	int (*bus_init)(struct i3c_master_controller *master);
@@ -447,6 +467,10 @@ struct i3c_master_controller_ops {
 	int (*disable_ibi)(struct i3c_dev_desc *dev);
 	void (*recycle_ibi_slot)(struct i3c_dev_desc *dev,
 				 struct i3c_ibi_slot *slot);
+	int (*request_mastership)(struct i3c_master_controller *master);
+	int (*enable_mr_events)(struct i3c_master_controller *master);
+	int (*disable_mr_events)(struct i3c_master_controller *master);
+	int (*populate_bus)(struct i3c_master_controller *master);
 };
 
 /**
@@ -488,6 +512,7 @@ struct i3c_master_controller {
 	} boardinfo;
 	struct i3c_bus bus;
 	struct workqueue_struct *wq;
+	bool want_to_acquire_bus;
 };
 
 /**
@@ -526,6 +551,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master);
 int i3c_master_get_free_addr(struct i3c_master_controller *master,
 			     u8 start_addr);
 
+int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
+				  u16 addr, u8 lvr);
 int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
 				  u8 addr);
 int i3c_master_do_daa(struct i3c_master_controller *master);
@@ -535,9 +562,14 @@ int i3c_master_init(struct i3c_master_controller *master,
 		    const struct i3c_master_controller_ops *ops,
 		    bool secondary);
 void i3c_master_cleanup(struct i3c_master_controller *master);
+int i3c_secondary_master_register(struct i3c_master_controller *master,
+				  struct i3c_device_info *info);
 int i3c_master_register(struct i3c_master_controller *master,
 			struct i3c_device_info *info);
 int i3c_master_unregister(struct i3c_master_controller *master);
+int i3c_master_mastership_ack(struct i3c_master_controller *master,
+			      u8 addr);
+void i3c_master_bus_takeover(struct i3c_master_controller *master);
 int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode);
 
 /**
@@ -648,7 +680,5 @@ void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot);
 
 struct i3c_ibi_slot *i3c_master_get_free_ibi_slot(struct i3c_dev_desc *dev);
 
-void i3c_bus_maintenance_lock(struct i3c_bus *bus);
-void i3c_bus_maintenance_unlock(struct i3c_bus *bus);
 
 #endif /* I3C_MASTER_H */
-- 
2.4.5


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v5 5/7] i3c: master: cdns: add support for mastership request to Cadence I3C master driver.
  2019-06-22 20:54 [PATCH v5 0/7] Add the I3C mastership request Przemyslaw Gaj
                   ` (3 preceding siblings ...)
  2019-06-22 20:55 ` [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem Przemyslaw Gaj
@ 2019-06-22 20:55 ` Przemyslaw Gaj
  2019-06-22 20:55 ` [PATCH v5 6/7] i3c: master: Add module author Przemyslaw Gaj
  2019-06-22 20:55 ` [PATCH v5 7/7] MAINTAINERS: add myself as co-maintainer of i3c subsystem Przemyslaw Gaj
  6 siblings, 0 replies; 21+ messages in thread
From: Przemyslaw Gaj @ 2019-06-22 20:55 UTC (permalink / raw)
  To: bbrezillon; +Cc: linux-i3c, agolec, Przemyslaw Gaj, rafalc, vitor.soares

This patch adds support for mastership request to Cadence I3C master driver.

Secondary master is registered only if primary master already assigned us a
dynamic address.

Mastership is requested automatically after secondary master
receives mastership ENEC event and core wants to acquire the bus.
This allows secondary masters to initialize their bus.

Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>

---

Main changes between v4 and v5:
- Add populate_bus() hook implementation
- Rework bus limitation/mode update
- Add support for i3c_secondary_master_register()
- Add support for DA updated interrupt

Main changes between v3 and v4:
- Refactored the code

Main changes between v2 and v3:
- Add mastership type
- Add postponed master registration
- Add update device definition on bus initialization time
- Removed redundant mastership work structs
- Reworked IBI slot lookup
- Reworked Mastership event enabling/disabling

Changes in v2:
- Add work structs for mastership purpose
- Add missing mastership disable feature
---
 drivers/i3c/master/i3c-master-cdns.c | 794 +++++++++++++++++++++++++++--------
 1 file changed, 621 insertions(+), 173 deletions(-)

diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
index 9706426..1577bf4 100644
--- a/drivers/i3c/master/i3c-master-cdns.c
+++ b/drivers/i3c/master/i3c-master-cdns.c
@@ -157,6 +157,7 @@
 #define SLV_IMR				0x48
 #define SLV_ICR				0x4c
 #define SLV_ISR				0x50
+#define SLV_INT_DEFSLVS			BIT(21)
 #define SLV_INT_TM			BIT(20)
 #define SLV_INT_ERROR			BIT(19)
 #define SLV_INT_EVENT_UP		BIT(18)
@@ -388,8 +389,18 @@ struct cdns_i3c_xfer {
 	struct cdns_i3c_cmd cmds[0];
 };
 
+enum cdns_i3c_mr {
+	REQUEST,
+	HANDOFF,
+	TAKEOVER
+};
 struct cdns_i3c_master {
 	struct work_struct hj_work;
+	struct {
+		struct work_struct work;
+		enum cdns_i3c_mr mr_type;
+		u32 ibir;
+	} mastership;
 	struct i3c_master_controller base;
 	u32 free_rr_slots;
 	unsigned int maxdevs;
@@ -408,6 +419,7 @@ struct cdns_i3c_master {
 	struct clk *pclk;
 	struct cdns_i3c_master_caps caps;
 	unsigned long i3c_scl_lim;
+	struct work_struct register_work;
 };
 
 static inline struct cdns_i3c_master *
@@ -663,6 +675,277 @@ static void cdns_i3c_master_unqueue_xfer(struct cdns_i3c_master *master,
 	spin_unlock_irqrestore(&master->xferqueue.lock, flags);
 }
 
+static void
+cdns_i3c_master_dev_rr_to_i3c_info(struct cdns_i3c_master *master,
+				   unsigned int slot,
+				   struct i3c_device_info *info)
+{
+	u32 rr;
+
+	memset(info, 0, sizeof(*info));
+	rr = readl(master->regs + DEV_ID_RR0(slot));
+	info->dyn_addr = DEV_ID_RR0_GET_DEV_ADDR(rr);
+	rr = readl(master->regs + DEV_ID_RR2(slot));
+	info->dcr = rr;
+	info->bcr = rr >> 8;
+	info->pid = rr >> 16;
+	info->pid |= (u64)readl(master->regs + DEV_ID_RR1(slot)) << 16;
+}
+
+static void
+cdns_i3c_master_dev_rr_to_i2c_info(struct cdns_i3c_master *master,
+				   unsigned int slot,
+				   u16 *addr, u8 *lvr)
+{
+	u32 rr;
+
+	rr = readl(master->regs + DEV_ID_RR0(slot));
+	*addr = DEV_ID_RR0_GET_DEV_ADDR(rr);
+	rr = readl(master->regs + DEV_ID_RR2(slot));
+	*lvr = rr;
+}
+
+static
+int cdns_i3c_master_request_mastership(struct i3c_master_controller *m)
+{
+	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+	u32 status;
+	int ret;
+
+	status = readl(master->regs + MST_STATUS0);
+	if (WARN_ON(status & MST_STATUS0_MASTER_MODE))
+		return -EEXIST;
+
+	status = readl(master->regs + SLV_STATUS1);
+	if (status & SLV_STATUS1_MR_DIS)
+		return -EACCES;
+
+	writel(readl(master->regs + CTRL) | CTRL_MST_INIT | CTRL_MST_ACK,
+	       master->regs + CTRL);
+
+	ret = readl_poll_timeout(master->regs + MST_STATUS0, status,
+				 status & MST_STATUS0_MASTER_MODE, 100,
+				 100000);
+	if (ret)
+		return ret;
+
+	writel(SLV_INT_EVENT_UP, master->regs + SLV_IDR);
+
+	master->base.bus.cur_master = master->base.this;
+
+	master->mastership.mr_type = TAKEOVER;
+	queue_work(master->base.wq, &master->mastership.work);
+
+	return 0;
+}
+
+static void cdns_i3c_master_upd_i3c_scl_lim(struct cdns_i3c_master *master)
+{
+	struct i3c_master_controller *m = &master->base;
+	unsigned long i3c_lim_period, pres_step, ncycles;
+	struct i3c_bus *bus = i3c_master_get_bus(m);
+	unsigned long new_i3c_scl_lim = 0;
+	struct i3c_dev_desc *dev;
+	u32 prescl1, ctrl;
+
+	i3c_bus_for_each_i3cdev(bus, dev) {
+		unsigned long max_fscl;
+
+		max_fscl = max(I3C_CCC_MAX_SDR_FSCL(dev->info.max_read_ds),
+			       I3C_CCC_MAX_SDR_FSCL(dev->info.max_write_ds));
+		switch (max_fscl) {
+		case I3C_SDR1_FSCL_8MHZ:
+			max_fscl = 8000000;
+			break;
+		case I3C_SDR2_FSCL_6MHZ:
+			max_fscl = 6000000;
+			break;
+		case I3C_SDR3_FSCL_4MHZ:
+			max_fscl = 4000000;
+			break;
+		case I3C_SDR4_FSCL_2MHZ:
+			max_fscl = 2000000;
+			break;
+		case I3C_SDR0_FSCL_MAX:
+		default:
+			max_fscl = 0;
+			break;
+		}
+
+		if (max_fscl &&
+		    (new_i3c_scl_lim > max_fscl || !new_i3c_scl_lim))
+			new_i3c_scl_lim = max_fscl;
+	}
+
+	/* Only update PRESCL_CTRL1 if the I3C SCL limitation has changed. */
+	if (new_i3c_scl_lim == master->i3c_scl_lim)
+		return;
+	master->i3c_scl_lim = new_i3c_scl_lim;
+	if (!new_i3c_scl_lim)
+		return;
+	pres_step = 1000000000UL / (bus->scl_rate.i3c * 4);
+
+	/* Configure PP_LOW to meet I3C slave limitations. */
+	prescl1 = readl(master->regs + PRESCL_CTRL1) &
+		  ~PRESCL_CTRL1_PP_LOW_MASK;
+	ctrl = readl(master->regs + CTRL);
+
+	i3c_lim_period = DIV_ROUND_UP(1000000000, master->i3c_scl_lim);
+	ncycles = DIV_ROUND_UP(i3c_lim_period, pres_step);
+	if (ncycles < 4)
+		ncycles = 0;
+	else
+		ncycles -= 4;
+
+	prescl1 |= PRESCL_CTRL1_PP_LOW(ncycles);
+
+	/* Disable I3C master before updating PRESCL_CTRL1. */
+	if (ctrl & CTRL_DEV_EN)
+		cdns_i3c_master_disable(master);
+
+	writel(prescl1, master->regs + PRESCL_CTRL1);
+
+	if (ctrl & CTRL_DEV_EN)
+		cdns_i3c_master_enable(master);
+}
+
+static int cdns_i3c_master_update_bus_limits(struct cdns_i3c_master *master)
+{
+	unsigned long pres_step, sysclk_rate, max_i2cfreq;
+	struct i3c_bus *bus = i3c_master_get_bus(&master->base);
+	u32 ctrl, prescl0, prescl1, pres, low;
+	int ncycles;
+
+	switch (bus->mode) {
+	case I3C_BUS_MODE_PURE:
+		ctrl = CTRL_PURE_BUS_MODE;
+		break;
+
+	case I3C_BUS_MODE_MIXED_FAST:
+		ctrl = CTRL_MIXED_FAST_BUS_MODE;
+		break;
+
+	case I3C_BUS_MODE_MIXED_SLOW:
+		ctrl = CTRL_MIXED_SLOW_BUS_MODE;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	sysclk_rate = clk_get_rate(master->sysclk);
+	if (!sysclk_rate)
+		return -EINVAL;
+
+	pres = DIV_ROUND_UP(sysclk_rate, (bus->scl_rate.i3c * 4)) - 1;
+	if (pres > PRESCL_CTRL0_MAX)
+		return -ERANGE;
+
+	bus->scl_rate.i3c = sysclk_rate / ((pres + 1) * 4);
+
+	prescl0 = PRESCL_CTRL0_I3C(pres);
+
+	low = ((I3C_BUS_TLOW_OD_MIN_NS * sysclk_rate) / (pres + 1)) - 2;
+	prescl1 = PRESCL_CTRL1_OD_LOW(low);
+
+	max_i2cfreq = bus->scl_rate.i2c;
+
+	pres = (sysclk_rate / (max_i2cfreq * 5)) - 1;
+	if (pres > PRESCL_CTRL0_MAX)
+		return -ERANGE;
+
+	bus->scl_rate.i2c = sysclk_rate / ((pres + 1) * 5);
+
+	ctrl = readl(master->regs + CTRL);
+
+	/* Disable I3C master before updating prescallers. */
+	if (ctrl & CTRL_DEV_EN)
+		cdns_i3c_master_disable(master);
+
+	prescl0 |= PRESCL_CTRL0_I2C(pres);
+	writel(prescl0, master->regs + PRESCL_CTRL0);
+
+	/* Calculate OD and PP low. */
+	pres_step = 1000000000 / (bus->scl_rate.i3c * 4);
+	ncycles = DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, pres_step) - 2;
+	if (ncycles < 0)
+		ncycles = 0;
+	prescl1 = PRESCL_CTRL1_OD_LOW(ncycles);
+
+	writel(prescl1, master->regs + PRESCL_CTRL1);
+
+	if (ctrl & CTRL_DEV_EN)
+		cdns_i3c_master_enable(master);
+
+	return 0;
+}
+
+static int cdns_i3c_master_populate_bus(struct i3c_master_controller *m)
+{
+	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+	enum i3c_bus_mode mode = m->bus.mode;
+	u32 val, newdevs;
+	u16 addr;
+	u8 lvr;
+	int slot, ret;
+	struct i3c_device_info i3c_info;
+
+	newdevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
+
+	for (slot = 1; slot <= master->maxdevs; slot++) {
+		val = readl(master->regs + DEV_ID_RR0(slot));
+
+		if ((newdevs & BIT(slot)) && (val & DEV_ID_RR0_IS_I3C)) {
+			cdns_i3c_master_dev_rr_to_i3c_info(master, slot,
+							   &i3c_info);
+
+			ret = i3c_master_add_i3c_dev_locked(m, i3c_info.dyn_addr);
+			if (ret && ret != -EBUSY)
+				dev_warn(&m->dev, "Cannot add I3C device with addr: 0x%.2x, (ret = %i)",
+					 i3c_info.dyn_addr, ret);
+		} else if ((newdevs & BIT(slot)) &&
+			   !(val & DEV_ID_RR0_IS_I3C)) {
+			cdns_i3c_master_dev_rr_to_i2c_info(master, slot,
+							   &addr, &lvr);
+
+			ret = i3c_master_add_i2c_dev_locked(m, addr, lvr);
+			if (ret && ret != -EBUSY) {
+				dev_warn(&m->dev, "Cannot add I2C device with addr: 0x%.2x, (ret = %i)",
+					 i3c_info.dyn_addr, ret);
+				continue;
+			}
+
+			switch (lvr & I3C_LVR_I2C_INDEX_MASK) {
+			case I3C_LVR_I2C_INDEX(0):
+				if (mode < I3C_BUS_MODE_MIXED_FAST)
+					mode = I3C_BUS_MODE_MIXED_FAST;
+				break;
+			case I3C_LVR_I2C_INDEX(1):
+			case I3C_LVR_I2C_INDEX(2):
+				if (mode < I3C_BUS_MODE_MIXED_SLOW)
+					mode = I3C_BUS_MODE_MIXED_SLOW;
+				break;
+			default:
+				continue;
+			}
+		}
+	}
+
+	cdns_i3c_master_upd_i3c_scl_lim(master);
+
+	ret = i3c_bus_set_mode(&m->bus, mode);
+	if (ret)
+		return ret;
+
+	/*
+	 * Update bus limits.
+	 */
+	ret = cdns_i3c_master_update_bus_limits(master);
+	if (ret)
+		return ret;
+
+	return 0;
+}
 static enum i3c_error_code cdns_i3c_cmd_get_err(struct cdns_i3c_cmd *cmd)
 {
 	switch (cmd->error) {
@@ -1037,91 +1320,6 @@ static void cdns_i3c_master_bus_cleanup(struct i3c_master_controller *m)
 	cdns_i3c_master_disable(master);
 }
 
-static void cdns_i3c_master_dev_rr_to_info(struct cdns_i3c_master *master,
-					   unsigned int slot,
-					   struct i3c_device_info *info)
-{
-	u32 rr;
-
-	memset(info, 0, sizeof(*info));
-	rr = readl(master->regs + DEV_ID_RR0(slot));
-	info->dyn_addr = DEV_ID_RR0_GET_DEV_ADDR(rr);
-	rr = readl(master->regs + DEV_ID_RR2(slot));
-	info->dcr = rr;
-	info->bcr = rr >> 8;
-	info->pid = rr >> 16;
-	info->pid |= (u64)readl(master->regs + DEV_ID_RR1(slot)) << 16;
-}
-
-static void cdns_i3c_master_upd_i3c_scl_lim(struct cdns_i3c_master *master)
-{
-	struct i3c_master_controller *m = &master->base;
-	unsigned long i3c_lim_period, pres_step, ncycles;
-	struct i3c_bus *bus = i3c_master_get_bus(m);
-	unsigned long new_i3c_scl_lim = 0;
-	struct i3c_dev_desc *dev;
-	u32 prescl1, ctrl;
-
-	i3c_bus_for_each_i3cdev(bus, dev) {
-		unsigned long max_fscl;
-
-		max_fscl = max(I3C_CCC_MAX_SDR_FSCL(dev->info.max_read_ds),
-			       I3C_CCC_MAX_SDR_FSCL(dev->info.max_write_ds));
-		switch (max_fscl) {
-		case I3C_SDR1_FSCL_8MHZ:
-			max_fscl = 8000000;
-			break;
-		case I3C_SDR2_FSCL_6MHZ:
-			max_fscl = 6000000;
-			break;
-		case I3C_SDR3_FSCL_4MHZ:
-			max_fscl = 4000000;
-			break;
-		case I3C_SDR4_FSCL_2MHZ:
-			max_fscl = 2000000;
-			break;
-		case I3C_SDR0_FSCL_MAX:
-		default:
-			max_fscl = 0;
-			break;
-		}
-
-		if (max_fscl &&
-		    (new_i3c_scl_lim > max_fscl || !new_i3c_scl_lim))
-			new_i3c_scl_lim = max_fscl;
-	}
-
-	/* Only update PRESCL_CTRL1 if the I3C SCL limitation has changed. */
-	if (new_i3c_scl_lim == master->i3c_scl_lim)
-		return;
-	master->i3c_scl_lim = new_i3c_scl_lim;
-	if (!new_i3c_scl_lim)
-		return;
-	pres_step = 1000000000UL / (bus->scl_rate.i3c * 4);
-
-	/* Configure PP_LOW to meet I3C slave limitations. */
-	prescl1 = readl(master->regs + PRESCL_CTRL1) &
-		  ~PRESCL_CTRL1_PP_LOW_MASK;
-	ctrl = readl(master->regs + CTRL);
-
-	i3c_lim_period = DIV_ROUND_UP(1000000000, master->i3c_scl_lim);
-	ncycles = DIV_ROUND_UP(i3c_lim_period, pres_step);
-	if (ncycles < 4)
-		ncycles = 0;
-	else
-		ncycles -= 4;
-
-	prescl1 |= PRESCL_CTRL1_PP_LOW(ncycles);
-
-	/* Disable I3C master before updating PRESCL_CTRL1. */
-	if (ctrl & CTRL_DEV_EN)
-		cdns_i3c_master_disable(master);
-
-	writel(prescl1, master->regs + PRESCL_CTRL1);
-
-	if (ctrl & CTRL_DEV_EN)
-		cdns_i3c_master_enable(master);
-}
 
 static int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
 {
@@ -1180,9 +1378,6 @@ static int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
 
 	cdns_i3c_master_upd_i3c_scl_lim(master);
 
-	/* Unmask Hot-Join and Mastership request interrupts. */
-	i3c_master_enec_locked(m, I3C_BROADCAST_ADDR,
-			       I3C_CCC_EVENT_HJ | I3C_CCC_EVENT_MR);
 
 	return 0;
 }
@@ -1190,61 +1385,15 @@ static int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
 static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
 {
 	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
-	unsigned long pres_step, sysclk_rate, max_i2cfreq;
-	struct i3c_bus *bus = i3c_master_get_bus(m);
-	u32 ctrl, prescl0, prescl1, pres, low;
-	int ncycles;
-
-	switch (bus->mode) {
-	case I3C_BUS_MODE_PURE:
-		ctrl = CTRL_PURE_BUS_MODE;
-		break;
-
-	case I3C_BUS_MODE_MIXED_FAST:
-		ctrl = CTRL_MIXED_FAST_BUS_MODE;
-		break;
-
-	case I3C_BUS_MODE_MIXED_SLOW:
-		ctrl = CTRL_MIXED_SLOW_BUS_MODE;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	sysclk_rate = clk_get_rate(master->sysclk);
-	if (!sysclk_rate)
-		return -EINVAL;
-
-	pres = DIV_ROUND_UP(sysclk_rate, (bus->scl_rate.i3c * 4)) - 1;
-	if (pres > PRESCL_CTRL0_MAX)
-		return -ERANGE;
-
-	bus->scl_rate.i3c = sysclk_rate / ((pres + 1) * 4);
-
-	prescl0 = PRESCL_CTRL0_I3C(pres);
-
-	low = ((I3C_BUS_TLOW_OD_MIN_NS * sysclk_rate) / (pres + 1)) - 2;
-	prescl1 = PRESCL_CTRL1_OD_LOW(low);
-
-	max_i2cfreq = bus->scl_rate.i2c;
-
-	pres = (sysclk_rate / (max_i2cfreq * 5)) - 1;
-	if (pres > PRESCL_CTRL0_MAX)
-		return -ERANGE;
-
-	bus->scl_rate.i2c = sysclk_rate / ((pres + 1) * 5);
-
-	prescl0 |= PRESCL_CTRL0_I2C(pres);
-	writel(prescl0, master->regs + PRESCL_CTRL0);
+	u32 ctrl;
+	int ret;
 
-	/* Calculate OD and PP low. */
-	pres_step = 1000000000 / (bus->scl_rate.i3c * 4);
-	ncycles = DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, pres_step) - 2;
-	if (ncycles < 0)
-		ncycles = 0;
-	prescl1 = PRESCL_CTRL1_OD_LOW(ncycles);
-	writel(prescl1, master->regs + PRESCL_CTRL1);
+	/*
+	 * Update bus limits.
+	 */
+	ret = cdns_i3c_master_update_bus_limits(master);
+	if (ret)
+		return ret;
 
 	/*
 	 * Enable Hot-Join, and, when a Hot-Join request happens, disable all
@@ -1252,6 +1401,7 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
 	 *
 	 * We will issue ENTDAA afterwards from the threaded IRQ handler.
 	 */
+	ctrl = readl(master->regs + CTRL);
 	ctrl |= CTRL_HJ_ACK | CTRL_HJ_DISEC | CTRL_HALT_EN | CTRL_MCS_EN;
 	writel(ctrl, master->regs + CTRL);
 
@@ -1260,6 +1410,22 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
 	return 0;
 }
 
+static
+struct i3c_dev_desc *cdns_i3c_get_ibi_device(struct cdns_i3c_master *master,
+					     u32 ibir)
+{
+	struct i3c_dev_desc *dev;
+	u32 id = IBIR_SLVID(ibir);
+
+	if (id >= master->ibi.num_slots || (ibir & IBIR_ERROR))
+		return NULL;
+
+	dev = master->ibi.slots[id];
+	if (!dev)
+		return NULL;
+
+	return dev;
+}
 static void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master,
 				       u32 ibir)
 {
@@ -1337,28 +1503,98 @@ static void cnds_i3c_master_demux_ibis(struct cdns_i3c_master *master)
 
 		case IBIR_TYPE_MR:
 			WARN_ON(IBIR_XFER_BYTES(ibir) || (ibir & IBIR_ERROR));
+			master->mastership.ibir = ibir;
+			master->mastership.mr_type = HANDOFF;
+			queue_work(master->base.wq,
+				   &master->mastership.work);
+			break;
 		default:
 			break;
 		}
 	}
 }
 
+static void cdns_i3c_master_bus_handoff(struct cdns_i3c_master *master)
+{
+	struct i3c_dev_desc *dev;
+
+	dev = cdns_i3c_get_ibi_device(master, master->mastership.ibir);
+
+	writel(MST_INT_MR_DONE, master->regs + MST_ICR);
+	writel(SLV_INT_EVENT_UP, master->regs + SLV_IER);
+
+	master->base.bus.cur_master = dev;
+}
+
+static void cdns_i3c_master_mastership_takeover(struct cdns_i3c_master *master)
+{
+	i3c_master_bus_takeover(&master->base);
+
+	writel(readl(master->regs + CTRL) & ~CTRL_MST_ACK, master->regs + CTRL);
+	writel(SLV_INT_EVENT_UP, master->regs + SLV_IDR);
+}
+
+static void cdns_i3c_master_event_up(struct cdns_i3c_master *master)
+{
+	u32 status;
+
+	writel(SLV_INT_EVENT_UP, master->regs + SLV_ICR);
+	status = readl(master->regs + SLV_STATUS1);
+
+	if (!(status & SLV_STATUS1_MR_DIS) &&
+	    master->base.want_to_acquire_bus) {
+		master->mastership.mr_type = REQUEST;
+		queue_work(master->base.wq, &master->mastership.work);
+	}
+}
+
+static void cdns_i3c_sec_master_da_updated(struct cdns_i3c_master *master)
+{
+	u32 status;
+
+	writel(SLV_INT_DA_UPD, master->regs + SLV_ICR);
+
+	status = readl(master->regs + SLV_STATUS1);
+
+	if (status & SLV_STATUS1_HAS_DA) {
+		writel(SLV_INT_DA_UPD, master->regs + SLV_IDR);
+		queue_work(master->base.wq, &master->register_work);
+	}
+}
 static irqreturn_t cdns_i3c_master_interrupt(int irq, void *data)
 {
 	struct cdns_i3c_master *master = data;
 	u32 status;
 
-	status = readl(master->regs + MST_ISR);
-	if (!(status & readl(master->regs + MST_IMR)))
-		return IRQ_NONE;
+	if (!master->base.this ||
+	    master->base.this != master->base.bus.cur_master) {
+		status = (readl(master->regs + SLV_ISR) &
+			  readl(master->regs + SLV_IMR));
+
+		if (!(status))
+			return IRQ_NONE;
+
+		if (status & SLV_INT_EVENT_UP)
+			cdns_i3c_master_event_up(master);
+
+		if (status & SLV_INT_DA_UPD)
+			cdns_i3c_sec_master_da_updated(master);
+	} else {
+		status = readl(master->regs + MST_ISR);
+
+		if (!(status & readl(master->regs + MST_IMR)))
+			return IRQ_NONE;
 
-	spin_lock(&master->xferqueue.lock);
-	cdns_i3c_master_end_xfer_locked(master, status);
-	spin_unlock(&master->xferqueue.lock);
+		spin_lock(&master->xferqueue.lock);
+		cdns_i3c_master_end_xfer_locked(master, status);
+		spin_unlock(&master->xferqueue.lock);
 
-	if (status & MST_INT_IBIR_THR)
-		cnds_i3c_master_demux_ibis(master);
+		if (status & MST_INT_IBIR_THR)
+			cnds_i3c_master_demux_ibis(master);
 
+		if (status & MST_INT_MR_DONE)
+			cdns_i3c_master_bus_handoff(master);
+	}
 	return IRQ_HANDLED;
 }
 
@@ -1426,30 +1662,55 @@ static int cdns_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
 	return ret;
 }
 
-static int cdns_i3c_master_request_ibi(struct i3c_dev_desc *dev,
-				       const struct i3c_ibi_setup *req)
+static int cdns_i3c_master_find_ibi_slot(struct cdns_i3c_master *master,
+					 struct i3c_dev_desc *dev,
+					 s16 *slot)
 {
-	struct i3c_master_controller *m = i3c_dev_get_master(dev);
-	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
-	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
 	unsigned long flags;
 	unsigned int i;
 
-	data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req);
-	if (IS_ERR(data->ibi_pool))
-		return PTR_ERR(data->ibi_pool);
+	int ret = -ENOENT;
 
 	spin_lock_irqsave(&master->ibi.lock, flags);
 	for (i = 0; i < master->ibi.num_slots; i++) {
-		if (!master->ibi.slots[i]) {
-			data->ibi = i;
-			master->ibi.slots[i] = dev;
+		/*
+		 * We only need 'SIR' slots to describe IBI-capable devices.
+		 * This slot may be used by mastership request interrupt,
+		 * We can ruse the same 'SIR' map entry.
+		 */
+		if (master->ibi.slots[i] == dev) {
+			*slot = i;
+			ret = 0;
 			break;
 		}
 	}
+
+	if (ret)
+		for (i = 0; i < master->ibi.num_slots; i++) {
+			if (!master->ibi.slots[i]) {
+				master->ibi.slots[i] = dev;
+				*slot = i;
+				ret = 0;
+				break;
+			}
+		}
 	spin_unlock_irqrestore(&master->ibi.lock, flags);
 
-	if (i < master->ibi.num_slots)
+	return ret;
+}
+
+static int cdns_i3c_master_request_ibi(struct i3c_dev_desc *dev,
+				       const struct i3c_ibi_setup *req)
+{
+	struct i3c_master_controller *m = i3c_dev_get_master(dev);
+	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+
+	data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req);
+	if (IS_ERR(data->ibi_pool))
+		return PTR_ERR(data->ibi_pool);
+
+	if (cdns_i3c_master_find_ibi_slot(master, dev, &data->ibi) == 0)
 		return 0;
 
 	i3c_generic_ibi_free_pool(data->ibi_pool);
@@ -1458,6 +1719,50 @@ static int cdns_i3c_master_request_ibi(struct i3c_dev_desc *dev,
 	return -ENOSPC;
 }
 
+static int
+cdns_i3c_master_enable_mastership_events(struct i3c_master_controller *m)
+{
+	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+	struct cdns_i3c_i2c_dev_data *data;
+	struct i3c_dev_desc *i3cdev;
+	unsigned long flags;
+	u32 sircfg, sirmap;
+	int ret;
+
+	i3c_bus_for_each_i3cdev(&m->bus, i3cdev) {
+		if (I3C_BCR_DEVICE_ROLE(i3cdev->info.bcr) != I3C_BCR_I3C_MASTER)
+			continue;
+
+		data = i3c_dev_get_master_data(i3cdev);
+		if (!data)
+			continue;
+
+		ret = cdns_i3c_master_find_ibi_slot(master, i3cdev, &data->ibi);
+		if (ret)
+			continue;
+
+		spin_lock_irqsave(&master->ibi.lock, flags);
+		sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi));
+		sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi);
+		sircfg = SIR_MAP_DEV_ROLE(i3cdev->info.bcr >> 6) |
+			SIR_MAP_DEV_DA(i3cdev->info.dyn_addr) |
+			SIR_MAP_DEV_PL(i3cdev->info.max_ibi_len) |
+			SIR_MAP_DEV_ACK;
+
+		if (i3cdev->info.bcr & I3C_BCR_MAX_DATA_SPEED_LIM)
+			sircfg |= SIR_MAP_DEV_SLOW;
+
+		sirmap |= SIR_MAP_DEV_CONF(data->ibi, sircfg);
+		writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi));
+		spin_unlock_irqrestore(&master->ibi.lock, flags);
+	}
+
+	/* Unmask Hot-Join and Mastership request interrupts. */
+	ret = i3c_master_enec_locked(&master->base, I3C_BROADCAST_ADDR,
+				     I3C_CCC_EVENT_HJ | I3C_CCC_EVENT_MR);
+
+	return ret;
+}
 static void cdns_i3c_master_free_ibi(struct i3c_dev_desc *dev)
 {
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
@@ -1473,6 +1778,51 @@ static void cdns_i3c_master_free_ibi(struct i3c_dev_desc *dev)
 	i3c_generic_ibi_free_pool(data->ibi_pool);
 }
 
+static int
+cdns_i3c_master_disable_mastership_events(struct i3c_master_controller *m)
+{
+	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+	struct cdns_i3c_i2c_dev_data *data;
+	struct i3c_dev_desc *i3cdev;
+	unsigned long flags;
+	u32 sirmap;
+	int ret;
+
+	ret = i3c_master_disec_locked(m, I3C_BROADCAST_ADDR,
+				      I3C_CCC_EVENT_MR);
+	if (ret)
+		return ret;
+
+	i3c_bus_for_each_i3cdev(&m->bus, i3cdev) {
+		if (I3C_BCR_DEVICE_ROLE(i3cdev->info.bcr) != I3C_BCR_I3C_MASTER)
+			continue;
+
+		data = i3c_dev_get_master_data(i3cdev);
+
+		ret = cdns_i3c_master_find_ibi_slot(master, i3cdev, &data->ibi);
+		if (ret)
+			continue;
+
+		/*
+		 * Do not modify SIR register and cleanup slots
+		 * if regular IBI is enabled for this device.
+		 */
+		if (master->ibi.slots[data->ibi]->ibi->handler)
+			continue;
+
+		spin_lock_irqsave(&master->ibi.lock, flags);
+		sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi));
+		sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi);
+		sirmap |= SIR_MAP_DEV_CONF(data->ibi,
+					SIR_MAP_DEV_DA(I3C_BROADCAST_ADDR));
+		writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi));
+		spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+		cdns_i3c_master_free_ibi(i3cdev);
+	}
+
+	return ret;
+}
 static void cdns_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
 					     struct i3c_ibi_slot *slot)
 {
@@ -1499,6 +1849,10 @@ static const struct i3c_master_controller_ops cdns_i3c_master_ops = {
 	.request_ibi = cdns_i3c_master_request_ibi,
 	.free_ibi = cdns_i3c_master_free_ibi,
 	.recycle_ibi_slot = cdns_i3c_master_recycle_ibi_slot,
+	.request_mastership = cdns_i3c_master_request_mastership,
+	.enable_mr_events = cdns_i3c_master_enable_mastership_events,
+	.disable_mr_events = cdns_i3c_master_disable_mastership_events,
+	.populate_bus = cdns_i3c_master_populate_bus
 };
 
 static void cdns_i3c_master_hj(struct work_struct *work)
@@ -1510,10 +1864,83 @@ static void cdns_i3c_master_hj(struct work_struct *work)
 	i3c_master_do_daa(&master->base);
 }
 
+static void
+cdns_i3c_master_mastership_request(struct cdns_i3c_master *master)
+{
+	u32 val;
+	int ret;
+
+	val = readl(master->regs + SLV_STATUS1);
+
+	if (!(val & SLV_STATUS1_HAS_DA))
+		return;
+
+	ret = cdns_i3c_master_request_mastership(&master->base);
+	if (ret)
+		dev_err(&master->base.dev, "Mastership failed\n");
+}
+
+static void cdns_i3c_master_mastership_handoff(struct cdns_i3c_master *master)
+{
+	int ret;
+
+	struct i3c_dev_desc *dev;
+	u32 ibir = master->mastership.ibir;
+
+	dev = cdns_i3c_get_ibi_device(master, ibir);
+	if (!dev)
+		return;
+
+	ret = i3c_master_mastership_ack(&master->base, dev->info.dyn_addr);
+	if (ret)
+		dev_err(&master->base.dev, "Mastership handoff failed\n");
+}
+
+static void cdns_i3c_master_mastership(struct work_struct *work)
+{
+	struct cdns_i3c_master *master = container_of(work,
+						      struct cdns_i3c_master,
+						      mastership.work);
+
+	switch (master->mastership.mr_type) {
+	case REQUEST:
+		cdns_i3c_master_mastership_request(master);
+		break;
+	case HANDOFF:
+		cdns_i3c_master_mastership_handoff(master);
+		break;
+	case TAKEOVER:
+		cdns_i3c_master_mastership_takeover(master);
+		break;
+	default:
+		break;
+	}
+}
+
+static void cdns_i3c_master_postponed_register(struct work_struct *work)
+{
+	struct cdns_i3c_master *master = container_of(work,
+						      struct cdns_i3c_master,
+						      register_work);
+	struct i3c_device_info info = { };
+	int ret;
+
+	cdns_i3c_master_dev_rr_to_i3c_info(master, 0, &info);
+	if (info.bcr & I3C_BCR_HDR_CAP)
+		info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
+
+	ret = i3c_secondary_master_register(&master->base, &info);
+	if (ret)
+		dev_warn(&master->base.dev,
+			 "Device registration failed (ret = %i)", ret);
+	else
+		writel(SLV_INT_EVENT_UP, master->regs + SLV_IER);
+}
 static int cdns_i3c_master_probe(struct platform_device *pdev)
 {
 	struct cdns_i3c_master *master;
 	struct resource *res;
+	bool secondary = false;
 	struct i3c_device_info info = { };
 	int ret, irq;
 	u32 val;
@@ -1555,7 +1982,10 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
 	spin_lock_init(&master->xferqueue.lock);
 	INIT_LIST_HEAD(&master->xferqueue.list);
 
+	INIT_WORK(&master->register_work, cdns_i3c_master_postponed_register);
 	INIT_WORK(&master->hj_work, cdns_i3c_master_hj);
+	INIT_WORK(&master->mastership.work,
+		  cdns_i3c_master_mastership);
 	writel(0xffffffff, master->regs + MST_IDR);
 	writel(0xffffffff, master->regs + SLV_IDR);
 	ret = devm_request_irq(&pdev->dev, irq, cdns_i3c_master_interrupt, 0,
@@ -1565,6 +1995,9 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, master);
 
+	val = readl(master->regs + MST_STATUS0);
+	if (!(val & MST_STATUS0_MASTER_MODE))
+		secondary = true;
 	val = readl(master->regs + CONF_STATUS0);
 
 	/* Device ID0 is reserved to describe this master. */
@@ -1588,25 +2021,39 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
 
 	writel(IBIR_THR(1), master->regs + CMD_IBI_THR_CTRL);
 	writel(MST_INT_IBIR_THR, master->regs + MST_IER);
-	writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
+	if (!secondary)
+		writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
 
-	ret = i3c_master_init(&master->base, &pdev->dev, &cdns_i3c_master_ops, false);
+	ret = i3c_master_init(&master->base, &pdev->dev,
+			      &cdns_i3c_master_ops, secondary);
 	if (ret)
-	goto err_disable_sysclk;
+		goto err_disable_sysclk;
 
-	/* Get an address for the master. */
-	ret = i3c_master_get_free_addr(&master->base, 0);
-	if (ret < 0)
-		return ret;
+	if (!secondary) {
+		/* Get an address for the master. */
+		ret = i3c_master_get_free_addr(&master->base, 0);
+		if (ret < 0)
+			return ret;
 
-	writel(prepare_rr0_dev_address(ret) | DEV_ID_RR0_IS_I3C,
-	       master->regs + DEV_ID_RR0(0));
+		writel(prepare_rr0_dev_address(ret) | DEV_ID_RR0_IS_I3C,
+		master->regs + DEV_ID_RR0(0));
+	}
 
-	cdns_i3c_master_dev_rr_to_info(master, 0, &info);
+	cdns_i3c_master_dev_rr_to_i3c_info(master, 0, &info);
 	if (info.bcr & I3C_BCR_HDR_CAP)
 		info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
 
-	ret = i3c_master_register(&master->base, &info);
+	if (secondary) {
+		if (readl(master->regs + SLV_STATUS1) & SLV_STATUS1_HAS_DA) {
+			ret = i3c_secondary_master_register(&master->base,
+							    &info);
+			if (master->base.want_to_acquire_bus)
+				writel(SLV_INT_EVENT_UP,
+				       master->regs + SLV_IER);
+		} else
+			writel(SLV_INT_DA_UPD, master->regs + SLV_IER);
+	} else
+		ret = i3c_master_register(&master->base, &info);
 
 	if (ret)
 		goto err_cleanup;
@@ -1656,6 +2103,7 @@ static struct platform_driver cdns_i3c_master = {
 module_platform_driver(cdns_i3c_master);
 
 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>");
+MODULE_AUTHOR("Przemyslaw Gaj <pgaj@cadence.com>");
 MODULE_DESCRIPTION("Cadence I3C master driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:cdns-i3c-master");
-- 
2.4.5


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v5 6/7] i3c: master: Add module author
  2019-06-22 20:54 [PATCH v5 0/7] Add the I3C mastership request Przemyslaw Gaj
                   ` (4 preceding siblings ...)
  2019-06-22 20:55 ` [PATCH v5 5/7] i3c: master: cdns: add support for mastership request to Cadence I3C master driver Przemyslaw Gaj
@ 2019-06-22 20:55 ` Przemyslaw Gaj
  2019-06-22 20:55 ` [PATCH v5 7/7] MAINTAINERS: add myself as co-maintainer of i3c subsystem Przemyslaw Gaj
  6 siblings, 0 replies; 21+ messages in thread
From: Przemyslaw Gaj @ 2019-06-22 20:55 UTC (permalink / raw)
  To: bbrezillon; +Cc: linux-i3c, agolec, Przemyslaw Gaj, rafalc, vitor.soares

This adds myself as an author of I3C framework.

Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
---
 drivers/i3c/master.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 3b44e66..5186b55 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2018 Cadence Design Systems Inc.
  *
  * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ * Author: Przemyslaw Gaj <pgaj@cadence.com>
  */
 
 #include <linux/atomic.h>
@@ -3098,5 +3099,6 @@ static void __exit i3c_exit(void)
 module_exit(i3c_exit);
 
 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>");
+MODULE_AUTHOR("Przemyslaw Gaj <pgaj@cadence.com>");
 MODULE_DESCRIPTION("I3C core");
 MODULE_LICENSE("GPL v2");
-- 
2.4.5


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v5 7/7] MAINTAINERS: add myself as co-maintainer of i3c subsystem
  2019-06-22 20:54 [PATCH v5 0/7] Add the I3C mastership request Przemyslaw Gaj
                   ` (5 preceding siblings ...)
  2019-06-22 20:55 ` [PATCH v5 6/7] i3c: master: Add module author Przemyslaw Gaj
@ 2019-06-22 20:55 ` Przemyslaw Gaj
  6 siblings, 0 replies; 21+ messages in thread
From: Przemyslaw Gaj @ 2019-06-22 20:55 UTC (permalink / raw)
  To: bbrezillon; +Cc: linux-i3c, agolec, Przemyslaw Gaj, rafalc, vitor.soares

As discussed with Boris Brezillon - I'm adding myself as the co-maintainer.

Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index dce5c09..a5003bd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7175,6 +7175,7 @@ F:	drivers/i2c/i2c-stub.c
 
 I3C SUBSYSTEM
 M:	Boris Brezillon <bbrezillon@kernel.org>
+M:	Przemyslaw Gaj <pgaj@cadence.com>
 L:	linux-i3c@lists.infradead.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux.git
 S:	Maintained
-- 
2.4.5


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 3/7] i3c: export i3c_bus_set_mode function
  2019-06-22 20:55 ` [PATCH v5 3/7] i3c: export i3c_bus_set_mode function Przemyslaw Gaj
@ 2019-07-06  7:39   ` Boris Brezillon
  0 siblings, 0 replies; 21+ messages in thread
From: Boris Brezillon @ 2019-07-06  7:39 UTC (permalink / raw)
  To: Przemyslaw Gaj; +Cc: linux-i3c, vitor.soares, rafalc, agolec, bbrezillon

On Sat, 22 Jun 2019 21:55:01 +0100
Przemyslaw Gaj <pgaj@cadence.com> wrote:

> I need to export this function to let secondary master update the bus mode.
> Some newly added I2C devices may operate in slower mode.
> 
> Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
> ---
>  drivers/i3c/master.c       | 10 ++++++++++
>  include/linux/i3c/master.h |  1 +
>  2 files changed, 11 insertions(+)
> 
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index 759078f..cbace14 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -566,6 +566,15 @@ static const struct device_type i3c_masterdev_type = {
>  	.groups	= i3c_masterdev_groups,
>  };
>  
> +/**
> + * i3c_bus_set_mode() - set a bus mode
> + * @i3cbus: I3C bus object
> + * @mode: new bus mode
> + *
> + * This is called at initialization time and should be called when
> + * bus mode has changed, for example when secondary master registered
> + * devices after successful masership takeover.
> + */
>  int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode)
>  {
>  	i3cbus->mode = mode;
> @@ -590,6 +599,7 @@ int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode)
>  
>  	return 0;
>  }
> +EXPORT_SYMBOL_GPL(i3c_bus_set_mode);

I'd rather not export this function and instead let the core decide
when the bus mode needs to be changed (based on the type of devices
added by the master).

>  
>  static struct i3c_master_controller *
>  i2c_adapter_to_i3c_master(struct i2c_adapter *adap)
> diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
> index df3d769..e089771 100644
> --- a/include/linux/i3c/master.h
> +++ b/include/linux/i3c/master.h
> @@ -538,6 +538,7 @@ void i3c_master_cleanup(struct i3c_master_controller *master);
>  int i3c_master_register(struct i3c_master_controller *master,
>  			struct i3c_device_info *info);
>  int i3c_master_unregister(struct i3c_master_controller *master);
> +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode);
>  
>  /**
>   * i3c_dev_get_master_data() - get master private data attached to an I3C


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 2/7] i3c: split i3c_master_register into init - register pair
  2019-06-22 20:55 ` [PATCH v5 2/7] i3c: split i3c_master_register into init - register pair Przemyslaw Gaj
@ 2019-07-06  8:48   ` Boris Brezillon
  2019-12-02 10:31   ` Przemyslaw Gaj
  1 sibling, 0 replies; 21+ messages in thread
From: Boris Brezillon @ 2019-07-06  8:48 UTC (permalink / raw)
  To: Przemyslaw Gaj; +Cc: linux-i3c, vitor.soares, rafalc, agolec, bbrezillon

On Sat, 22 Jun 2019 21:55:00 +0100
Przemyslaw Gaj <pgaj@cadence.com> wrote:

> This patch is base for mastership takeover where secondary master is
> initialized at probe time but register may be postponed till dynamic address is
> assigned to our device.
> 
> Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
> ---
>  drivers/i3c/master.c                 | 86 ++++++++++++++++++++----------------
>  drivers/i3c/master/dw-i3c-master.c   | 34 +++++++-------
>  drivers/i3c/master/i3c-master-cdns.c | 45 ++++++++++---------
>  include/linux/i3c/master.h           | 12 ++---
>  4 files changed, 94 insertions(+), 83 deletions(-)
> 
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index 0f7c31e..759078f 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -1528,32 +1528,9 @@ int i3c_master_do_daa(struct i3c_master_controller *master)
>  }
>  EXPORT_SYMBOL_GPL(i3c_master_do_daa);
>  
> -/**
> - * i3c_master_set_info() - set master device information
> - * @master: master used to send frames on the bus
> - * @info: I3C device information
> - *
> - * Set master device info. This should be called from
> - * &i3c_master_controller_ops->bus_init().
> - *
> - * Not all &i3c_device_info fields are meaningful for a master device.
> - * Here is a list of fields that should be properly filled:
> - *
> - * - &i3c_device_info->dyn_addr
> - * - &i3c_device_info->bcr
> - * - &i3c_device_info->dcr
> - * - &i3c_device_info->pid
> - * - &i3c_device_info->hdr_cap if %I3C_BCR_HDR_CAP bit is set in
> - *   &i3c_device_info->bcr
> - *
> - * This function must be called with the bus lock held in maintenance mode.
> - *
> - * Return: 0 if @info contains valid information (not every piece of
> - * information can be checked, but we can at least make sure @info->dyn_addr
> - * and @info->bcr are correct), -EINVAL otherwise.
> - */
> -int i3c_master_set_info(struct i3c_master_controller *master,
> -			const struct i3c_device_info *info)
> +static int i3c_master_set_info(struct i3c_master_controller *master,
> +			       const struct i3c_device_info *info,
> +			       bool secondary)

secondary is not used here, and this can be extracted from
master->secondary anyway. I think you can drop this argument.

>  {
>  	struct i3c_dev_desc *i3cdev;
>  	int ret;
> @@ -1586,7 +1563,6 @@ int i3c_master_set_info(struct i3c_master_controller *master,
>  
>  	return ret;
>  }
> -EXPORT_SYMBOL_GPL(i3c_master_set_info);
>  
>  static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
>  {
> @@ -2403,7 +2379,7 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
>  }
>  
>  /**
> - * i3c_master_register() - register an I3C master
> + * i3c_master_init() - initializes all the structures required by I3C master
>   * @master: master used to send frames on the bus
>   * @parent: the parent device (the one that provides this I3C master
>   *	    controller)
> @@ -2417,16 +2393,14 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
>   * - creates and initializes the I3C bus
>   * - populates the bus with static I2C devs if @parent->of_node is not
>   *   NULL
> - * - registers all I3C devices added by the controller during bus
> - *   initialization
> - * - registers the I2C adapter and all I2C devices
> + * - set bus mode when registering I2C devices.
>   *
>   * Return: 0 in case of success, a negative error code otherwise.
>   */
> -int i3c_master_register(struct i3c_master_controller *master,
> -			struct device *parent,
> -			const struct i3c_master_controller_ops *ops,
> -			bool secondary)
> +int i3c_master_init(struct i3c_master_controller *master,
> +		    struct device *parent,
> +		    const struct i3c_master_controller_ops *ops,
> +		    bool secondary)

Can we have i3c_primary_master_init() and i3c_secondary_master_init()
instead of this secondary arg? You can provide them as wrappers around a
generic i3c_master_init() if that make sense.

>  {
>  	struct i3c_bus *i3cbus = i3c_master_get_bus(master);
>  	enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
> @@ -2488,10 +2462,47 @@ int i3c_master_register(struct i3c_master_controller *master,
>  		ret = -ENOMEM;
>  		goto err_put_dev;
>  	}
> +	return 0;
> +
> +err_put_dev:
> +	put_device(&master->dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(i3c_master_init);

_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem
  2019-06-22 20:55 ` [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem Przemyslaw Gaj
@ 2019-07-06  9:00   ` Boris Brezillon
  2019-07-10 18:04   ` Vitor Soares
  1 sibling, 0 replies; 21+ messages in thread
From: Boris Brezillon @ 2019-07-06  9:00 UTC (permalink / raw)
  To: Przemyslaw Gaj; +Cc: linux-i3c, vitor.soares, rafalc, agolec, bbrezillon

On Sat, 22 Jun 2019 21:55:02 +0100
Przemyslaw Gaj <pgaj@cadence.com> wrote:


> diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
> index 86b7b44..cdfc5bf 100644
> --- a/drivers/i3c/internals.h
> +++ b/drivers/i3c/internals.h
> @@ -14,6 +14,10 @@ extern struct bus_type i3c_bus_type;
>  
>  void i3c_bus_normaluse_lock(struct i3c_bus *bus);
>  void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
> +void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> +void i3c_bus_maintenance_unlock(struct i3c_bus *bus);

I don't think you need to expose the maintenance lock helpers, looks
like they're only used in master.c.

> +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master);
> +
>  
>  int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
>  				 struct i3c_priv_xfer *xfers,
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index cbace14..3b44e66 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -93,6 +93,18 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
>  	up_read(&bus->lock);
>  }
>  
> +/*
> + * i3c_bus_downgrade_maintenance_lock - Downgrade the bus lock to normal
> + * operation
> + *
> + * Should be called when a maintenance operation is done and normal
> + * operation is planned. See i3c_bus_maintenance_lock() and
> + * i3c_bus_normaluse_lock() for more details.
> + */
> +static void i3c_bus_downgrade_maintenance_lock(struct i3c_bus *bus)
> +{
> +	downgrade_write(&bus->lock);
> +}

Missing blank line.

>  static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
>  {
>  	return container_of(dev, struct i3c_master_controller, dev);
> @@ -341,6 +353,22 @@ static int i3c_device_probe(struct device *dev)
>  	return driver->probe(i3cdev);
>  }
>  
> +static int
> +i3c_master_enable_mr_events_locked(struct i3c_master_controller *master)
> +{
> +	if (!master->ops->enable_mr_events)
> +		return -ENOTSUPP;
> +
> +	return master->ops->enable_mr_events(master);
> +}
> +
> +static void i3c_master_disable_mr_events(struct i3c_master_controller *master)
> +{
> +	if (!master->ops->disable_mr_events)
> +		return;
> +
> +	master->ops->disable_mr_events(master);
> +}

Missing blank line.

>  static int i3c_device_remove(struct device *dev)
>  {
>  	struct i3c_device *i3cdev = dev_to_i3cdev(dev);
> @@ -462,6 +490,42 @@ static int i3c_bus_init(struct i3c_bus *i3cbus)
>  	return 0;
>  }
>  
> +static int
> +i3c_master_request_mastership_locked(struct i3c_master_controller *master)
> +{
> +	if (WARN_ON(master->init_done &&
> +	    !rwsem_is_locked(&master->bus.lock)))

Hm, that looks suspicious. The lock should be held even if ->init_done
is false. Can you explain the difference between init_done
and !init_done?

> +		return -EINVAL;
> +
> +	if (!master->ops->request_mastership)
> +		return -ENOTSUPP;
> +
> +	return master->ops->request_mastership(master);
> +}
> +
> +static int i3c_master_owns_bus(struct i3c_master_controller *master)
> +{
> +	return (master->bus.cur_master == master->this);
> +}
> +
> +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master)
> +{
> +	int ret;
> +
> +	if (!i3c_master_owns_bus(master)) {
> +		i3c_bus_normaluse_unlock(&master->bus);
> +		i3c_bus_maintenance_lock(&master->bus);
> +
> +		ret = i3c_master_request_mastership_locked(master);
> +		if (ret) {
> +			i3c_bus_maintenance_unlock(&master->bus);
> +			return ret;
> +		}
> +		i3c_bus_downgrade_maintenance_lock(&master->bus);
> +	}

I think this block deserves a comment: the lock/unlock dance is far
from obvious.

> +
> +	return 0;
> +}
>  static const char * const i3c_bus_mode_strings[] = {
>  	[I3C_BUS_MODE_PURE] = "pure",
>  	[I3C_BUS_MODE_MIXED_FAST] = "mixed-fast",
> @@ -636,6 +700,22 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
>  	return dev;
>  }
>  
> +static struct i2c_dev_desc *
> +i3c_master_alloc_i2c_dev_no_boardinfo(struct i3c_master_controller *master,
> +				      u16 addr, u8 lvr)
> +{
> +	struct i2c_dev_desc *dev;
> +
> +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> +	if (!dev)
> +		return ERR_PTR(-ENOMEM);
> +
> +	dev->common.master = master;
> +	dev->addr = addr;
> +	dev->lvr = lvr;
> +
> +	return dev;
> +}
>  static void *i3c_ccc_cmd_dest_init(struct i3c_ccc_cmd_dest *dest, u8 addr,
>  				   u16 payloadlen)
>  {
> @@ -705,6 +785,8 @@ i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master,
>  	struct i2c_dev_desc *dev;
>  
>  	i3c_bus_for_each_i2cdev(&master->bus, dev) {
> +		if (!dev->boardinfo)
> +			continue;

Blank line here, please.

>  		if (dev->boardinfo->base.addr == addr)
>  			return dev;
>  	}
> @@ -1478,7 +1560,8 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
>  		return;
>  
>  	i3c_bus_for_each_i3cdev(&master->bus, desc) {
> -		if (desc->dev || !desc->info.dyn_addr || desc == master->this)
> +		if (desc->dev || !desc->info.dyn_addr ||
> +		    desc == master->this || !desc->info.pid)

Does the new logic trigger a case where pid == 0? The check looks good
anyway, but I'd rather have it in a separate commit unless you have a
good explanation on why this couldn't happen before this patch.

>  			continue;
>  
>  		desc->dev = kzalloc(sizeof(*desc->dev), GFP_KERNEL);
> @@ -1504,6 +1587,69 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
>  	}
>  }
>  
> +static struct i2c_dev_boardinfo *
> +i3c_master_find_i2c_boardinfo(const struct i3c_master_controller *master,
> +			      u16 addr, u8 lvr)
> +{
> +	struct i2c_dev_boardinfo *i2cboardinfo;
> +
> +	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
> +		if (i2cboardinfo->base.addr == addr &&
> +		    i2cboardinfo->lvr == lvr)
> +			return i2cboardinfo;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void
> +i3c_master_register_new_i2c_devs(struct i3c_master_controller *master)
> +{
> +	struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
> +	struct i2c_dev_desc *i2cdev;
> +
> +	if (!master->init_done)
> +		return;
> +
> +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> +

You can drop this blank line.

> +		if (i2cdev->dev)
> +			continue;
> +

Add a comment explaining why.

> +		if (!i2cdev->boardinfo)
> +			continue;
> +
> +		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
> +	}
> +}
> +
> +static int i3c_master_get_accmst_locked(struct i3c_master_controller *master,
> +					u8 addr)
> +{
> +	struct i3c_ccc_getaccmst *accmst;
> +	struct i3c_ccc_cmd_dest dest;
> +	struct i3c_ccc_cmd cmd;
> +	int ret;
> +
> +	accmst = i3c_ccc_cmd_dest_init(&dest, addr, sizeof(*accmst));
> +	if (!accmst)
> +		return -ENOMEM;
> +
> +	i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETACCMST, &dest, 1);
> +
> +	ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
> +	if (ret)
> +		goto out;
> +
> +	if (dest.payload.len != sizeof(*accmst))
> +		ret = -EIO;
> +
> +out:
> +	i3c_ccc_cmd_dest_cleanup(&dest);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(i3c_master_get_accmst_locked);

Add a blank line here (please run checkpatch --strict, it should
complain about such coding style issues).

>  /**
>   * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
>   * @master: master doing the DAA
> @@ -1548,10 +1694,6 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
>  	if (!i3c_bus_dev_addr_is_avail(&master->bus, info->dyn_addr))
>  		return -EINVAL;
>  
> -	if (I3C_BCR_DEVICE_ROLE(info->bcr) == I3C_BCR_I3C_MASTER &&
> -	    master->secondary)
> -		return -EINVAL;
> -
>  	if (master->this)
>  		return -EINVAL;
>  
> @@ -1560,7 +1702,8 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
>  		return PTR_ERR(i3cdev);
>  
>  	master->this = i3cdev;
> -	master->bus.cur_master = master->this;
> +	if (!secondary)
> +		master->bus.cur_master = master->this;
>  
>  	ret = i3c_master_attach_i3c_dev(master, i3cdev);
>  	if (ret)
> @@ -1601,37 +1744,7 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
>  	}
>  }
>  

[...]

> +/**
> + * i3c_master_bus_init() - initialize an I3C bus
> + * @master: main master initializing the bus
> + *
> + * This function is following all initialisation steps described in the I3C
> + * specification:
> + *
> + * 1. Attach I2C and statically defined I3C devs to the master so that the
> + *    master can fill its internal device table appropriately
> + *
> + * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
> + *    the master controller. That's usually where the bus mode is selected
> + *    (pure bus or mixed fast/slow bus)
> + *
> + * 3. Instruct all devices on the bus to drop their dynamic address. This is
> + *    particularly important when the bus was previously configured by someone
> + *    else (for example the bootloader)
> + *
> + * 4. Disable all slave events.
> + *
> + * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
> + *    devices that have a static address
> + *
> + * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
> + *    remaining I3C devices
> + *
> + * Once this is done, all I3C and I2C devices should be usable.
> + *
> + * Return: a 0 in case of success, an negative error code otherwise.
> + */
> +static int i3c_master_bus_init(struct i3c_master_controller *master)
> +{
> +	struct i3c_dev_desc *i3cdev;
> +	int ret;
> +
> +	/*
> +	 * First attach all devices with static definitions provided by the
> +	 * FW.
> +	 */
> +	ret = i3c_master_attach_static_devs(master);
> +	if (ret)
> +		goto err_detach_devs;
>  	/*
>  	 * Now execute the controller specific ->bus_init() routine, which
>  	 * might configure its internal logic to match the bus limitations.
> @@ -1780,45 +1926,76 @@ i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev)
>  }

The i3c_master_attach_static_devs() split can be done in a separate
commit. Please try to split things as much as possible to ease review.

>  
>  /**
> - * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> - * @master: master used to send frames on the bus
> - * @addr: I3C slave dynamic address assigned to the device
> + * i3c_master_add_i2c_dev_locked() - add an I2C slave to the bus
> + * @master: master used to register I2C device
> + * @addr: I2C device address
> + * @lvr: legacy virtual register value
>   *
> - * This function is instantiating an I3C device object and adding it to the
> - * I3C device list. All device information are automatically retrieved using
> - * standard CCC commands.
> - *
> - * The I3C device object is returned in case the master wants to attach
> - * private data to it using i3c_dev_set_master_data().
> + * This function is instantiating an I2C device object and adding it to the
> + * I2C device list.
>   *
>   * This function must be called with the bus lock held in write mode.
>   *
>   * Return: a 0 in case of success, an negative error code otherwise.
>   */
> -int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> -				  u8 addr)
> +int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
> +				  u16 addr, u8 lvr)
>  {
> -	struct i3c_device_info info = { .dyn_addr = addr };
> -	struct i3c_dev_desc *newdev, *olddev;
> -	u8 old_dyn_addr = addr, expected_dyn_addr;
> -	struct i3c_ibi_setup ibireq = { };
> -	bool enable_ibi = false;
> +	enum i3c_addr_slot_status status;
> +	struct i2c_dev_desc *i2cdev;
>  	int ret;
>  
>  	if (!master)
>  		return -EINVAL;
>  
> -	newdev = i3c_master_alloc_i3c_dev(master, &info);
> -	if (IS_ERR(newdev))
> -		return PTR_ERR(newdev);
> +	status = i3c_bus_get_addr_slot_status(&master->bus,
> +					      addr);
> +	if (status != I3C_ADDR_SLOT_FREE)
> +		return -EBUSY;
>  
> -	ret = i3c_master_attach_i3c_dev(master, newdev);
> -	if (ret)
> +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> +				     I3C_ADDR_SLOT_I2C_DEV);
> +
> +	i2cdev = i3c_master_alloc_i2c_dev_no_boardinfo(master, addr, lvr);
> +
> +	if (IS_ERR(i2cdev)) {
> +		ret = PTR_ERR(i2cdev);
> +		goto err_free_dev;
> +	}
> +
> +	i2cdev->boardinfo = i3c_master_find_i2c_boardinfo(master, addr, lvr);
> +
> +	ret = i3c_master_attach_i2c_dev(master, i2cdev);
> +
> +	if (ret) {
> +		ret = PTR_ERR(i2cdev);
>  		goto err_free_dev;
> +	}
> +
> +	return 0;
> +
> +err_free_dev:
> +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> +				     I3C_ADDR_SLOT_FREE);
> +	i3c_master_free_i2c_dev(i2cdev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(i3c_master_add_i2c_dev_locked);

Same here.

> +
> +static int
> +i3c_master_retrieve_info_and_reuse(struct i3c_master_controller *master,
> +				   struct i3c_dev_desc *newdev)
> +{
> +	struct i3c_dev_desc *olddev;
> +	u8 old_dyn_addr = newdev->info.dyn_addr, expected_dyn_addr;
> +	struct i3c_ibi_setup ibireq = { };
> +	bool enable_ibi = false;
> +	int ret;
>  
>  	ret = i3c_master_retrieve_dev_info(newdev);
>  	if (ret)
> -		goto err_detach_dev;
> +		return ret;
>  
>  	olddev = i3c_master_search_i3c_dev_duplicate(newdev);
>  	if (olddev) {
> @@ -1857,7 +2034,7 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
>  
>  	ret = i3c_master_reattach_i3c_dev(newdev, old_dyn_addr);
>  	if (ret)
> -		goto err_detach_dev;
> +		return ret;
>  
>  	/*
>  	 * Depending on our previous state, the expected dynamic address might
> @@ -1920,6 +2097,50 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
>  	}
>  
>  	return 0;
> +}
> +
> +/**
> + * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> + * @master: master used to send frames on the bus
> + * @addr: I3C slave dynamic address assigned to the device
> + *
> + * This function is instantiating an I3C device object and adding it to the
> + * I3C device list. All device information are automatically retrieved using
> + * standard CCC commands.
> + *
> + * The I3C device object is returned in case the master wants to attach
> + * private data to it using i3c_dev_set_master_data().
> + *
> + * This function must be called with the bus lock held in write mode.
> + *
> + * Return: a 0 in case of success, an negative error code otherwise.
> + */
> +int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> +				  u8 addr)
> +{
> +	struct i3c_device_info info = { .dyn_addr = addr };
> +	struct i3c_dev_desc *newdev;
> +	int ret;
> +
> +	if (!master)
> +		return -EINVAL;
> +
> +	newdev = i3c_master_alloc_i3c_dev(master, &info);
> +	if (IS_ERR(newdev))
> +		return PTR_ERR(newdev);
> +
> +	ret = i3c_master_attach_i3c_dev(master, newdev);
> +	if (ret)
> +		goto err_free_dev;
> +
> +	if (i3c_master_owns_bus(master)) {
> +		ret = i3c_master_retrieve_info_and_reuse(master, newdev);
> +		if (ret)
> +			goto err_detach_dev;
> +	} else
> +		master->want_to_acquire_bus = true;

Please add curly braces.

> +
> +	return 0;
>  
>  err_detach_dev:
>  	if (newdev->dev && newdev->dev->desc)
> @@ -2101,11 +2322,15 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
>  	}
>  
>  	i3c_bus_normaluse_lock(&master->bus);
> +	ret = i3c_master_acquire_bus_ownership(master);
> +	if (ret)
> +		goto err_unlock_bus;
>  	dev = i3c_master_find_i2c_dev_by_addr(master, addr);
>  	if (!dev)
>  		ret = -ENOENT;
>  	else
>  		ret = master->ops->i2c_xfers(dev, xfers, nxfers);
> +err_unlock_bus:
>  	i3c_bus_normaluse_unlock(&master->bus);
>  
>  	return ret ? ret : nxfers;
> @@ -2144,9 +2369,12 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
>  	 * We silently ignore failures here. The bus should keep working
>  	 * correctly even if one or more i2c devices are not registered.
>  	 */
> -	i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
> +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> +		if (!i2cdev->boardinfo)
> +			continue;
>  		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
>  
> +	}
>  	return 0;
>  }

[...]

>  /**
>   * i3c_master_init() - initializes all the structures required by I3C master
>   * @master: master used to send frames on the bus
> @@ -2417,9 +2712,6 @@ int i3c_master_init(struct i3c_master_controller *master,
>  	struct i2c_dev_boardinfo *i2cbi;
>  	int ret;
>  
> -	/* We do not support secondary masters yet. */
> -	if (secondary)
> -		return -ENOTSUPP;
>  
>  	ret = i3c_master_check_ops(ops);
>  	if (ret)
> @@ -2432,6 +2724,7 @@ int i3c_master_init(struct i3c_master_controller *master,
>  	master->dev.release = i3c_masterdev_release;
>  	master->ops = ops;
>  	master->secondary = secondary;
> +	master->want_to_acquire_bus = secondary;

Why do we need to set it to true here? Actually, I'm not even sure you
need that variable. Looks like it's only ever set, nothing reads it.

>  	INIT_LIST_HEAD(&master->boardinfo.i2c);
>  	INIT_LIST_HEAD(&master->boardinfo.i3c);
>  
> @@ -2488,6 +2781,92 @@ void i3c_master_cleanup(struct i3c_master_controller *master)
>  EXPORT_SYMBOL_GPL(i3c_master_cleanup);
>  

Overall, I like this version much better than the previous ones. Still
need some refinements though (and more documentation/comments to explain
how that works).


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem
  2019-06-22 20:55 ` [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem Przemyslaw Gaj
  2019-07-06  9:00   ` Boris Brezillon
@ 2019-07-10 18:04   ` Vitor Soares
  2019-07-11  5:28     ` Przemyslaw Gaj
  1 sibling, 1 reply; 21+ messages in thread
From: Vitor Soares @ 2019-07-10 18:04 UTC (permalink / raw)
  To: Przemyslaw Gaj, bbrezillon; +Cc: linux-i3c, agolec, rafalc, vitor.soares

From: Przemyslaw Gaj <pgaj@cadence.com>
Date: Sat, Jun 22, 2019 at 21:55:02

> This patch adds support for mastership request to I3C subsystem.
> 
> Mastership event is enabled globally.
> 
> Mastership is requested automatically when device driver
> tries to transfer data using master controller in slave mode.
> 
> There is still some limitation:
> - I2C devices are registered on secondary master side if boardinfo
> entry matching the info transmitted through the DEFSLVS frame.
> 
> Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
> 
> ---
> 
> Main changes between v4 and v5:
> - Add function to test if master owns the bus
> - Add i3c_secondary_master_register() function
> - Add populate_bus() hook to populate the bus after mastership takeover

For me this task is for the sub-system not the host controller.

> - Rework device information retrieval to allow adding partialy discovered
> devices
> 
> Main changes between v3 and v4:
> - Add i3c_master_acquire_bus_ownership to acquire the bus
> - Refactored the code
> 
> Main changes between v2 and v3:
> - Add i3c_bus_downgrade_maintenance_lock() for downgrading the bus
> lock from maintenance to normal use
> - Add additional fields to i2c_dev_desc for DEFSLVS purpose (addr, lvr)
> - Add i3c_master_register_new_i2c_devs() function to register I2C devices
> - Reworked I2C devices registration on secondary master side
> 
> Changes in v2:
> - Add mastership disable event hook
> - Changed name of mastership enable event hook
> - Add function to test if master owns the bus
> - Removed op_mode
> - Changed parameter of i3c_master_get_accmst_locked, no need to
> pass full i3c_device_info
> - Changed name of mastership enable event hook
> - Add function to test if master owns the bus
> - Removed op_mode
> - Changed parameter of i3c_master_get_accmst_locked, no need to
> pass full i3c_device_info
> - Removed redundant DEFSLVS command before GETACCMST
> - Add i3c_master_bus_takeover function. There is a need to lock
> the bus before adding devices and no matter of the controller
> devices have to be added after mastership takeover.
> - Add device registration during initialization on secondary master
> side. Devices received by DEFSLVS (if occured). If not, device
> initialization is deffered untill next mastership request.
> ---
>  drivers/i3c/device.c       |  26 ++
>  drivers/i3c/internals.h    |   4 +
>  drivers/i3c/master.c       | 588 ++++++++++++++++++++++++++++++++++++++-------
>  include/linux/i3c/master.h |  34 ++-
>  4 files changed, 563 insertions(+), 89 deletions(-)
> 
> diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
> index 69cc040..b60f637 100644
> --- a/drivers/i3c/device.c
> +++ b/drivers/i3c/device.c
> @@ -43,7 +43,13 @@ int i3c_device_do_priv_xfers(struct i3c_device *dev,
>  	}
>  
>  	i3c_bus_normaluse_lock(dev->bus);
> +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> +	if (ret)
> +		goto err_unlock_bus;
> +
>  	ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
> +
> +err_unlock_bus:
>  	i3c_bus_normaluse_unlock(dev->bus);
>  
>  	return ret;
> @@ -114,11 +120,17 @@ int i3c_device_enable_ibi(struct i3c_device *dev)
>  	int ret = -ENOENT;
>  
>  	i3c_bus_normaluse_lock(dev->bus);
> +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> +	if (ret)
> +		goto err_unlock_bus;
> +
>  	if (dev->desc) {
>  		mutex_lock(&dev->desc->ibi_lock);
>  		ret = i3c_dev_enable_ibi_locked(dev->desc);
>  		mutex_unlock(&dev->desc->ibi_lock);
>  	}
> +
> +err_unlock_bus:
>  	i3c_bus_normaluse_unlock(dev->bus);
>  
>  	return ret;
> @@ -145,11 +157,17 @@ int i3c_device_request_ibi(struct i3c_device *dev,
>  		return -EINVAL;
>  
>  	i3c_bus_normaluse_lock(dev->bus);
> +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> +	if (ret)
> +		goto err_unlock_bus;
> +
>  	if (dev->desc) {
>  		mutex_lock(&dev->desc->ibi_lock);
>  		ret = i3c_dev_request_ibi_locked(dev->desc, req);
>  		mutex_unlock(&dev->desc->ibi_lock);
>  	}
> +
> +err_unlock_bus:
>  	i3c_bus_normaluse_unlock(dev->bus);
>  
>  	return ret;
> @@ -166,12 +184,20 @@ EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
>   */
>  void i3c_device_free_ibi(struct i3c_device *dev)
>  {
> +	int ret;
> +
>  	i3c_bus_normaluse_lock(dev->bus);
> +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> +	if (ret)
> +		goto err_unlock_bus;
> +
>  	if (dev->desc) {
>  		mutex_lock(&dev->desc->ibi_lock);
>  		i3c_dev_free_ibi_locked(dev->desc);
>  		mutex_unlock(&dev->desc->ibi_lock);
>  	}
> +
> +err_unlock_bus:
>  	i3c_bus_normaluse_unlock(dev->bus);
>  }
>  EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
> diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
> index 86b7b44..cdfc5bf 100644
> --- a/drivers/i3c/internals.h
> +++ b/drivers/i3c/internals.h
> @@ -14,6 +14,10 @@ extern struct bus_type i3c_bus_type;
>  
>  void i3c_bus_normaluse_lock(struct i3c_bus *bus);
>  void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
> +void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> +void i3c_bus_maintenance_unlock(struct i3c_bus *bus);

These function are static.

> +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master);
> +

What do you think to pass this logic to master.c?

>  
>  int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
>  				 struct i3c_priv_xfer *xfers,
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index cbace14..3b44e66 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -93,6 +93,18 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
>  	up_read(&bus->lock);
>  }
>  
> +/*
> + * i3c_bus_downgrade_maintenance_lock - Downgrade the bus lock to normal
> + * operation
> + *
> + * Should be called when a maintenance operation is done and normal
> + * operation is planned. See i3c_bus_maintenance_lock() and
> + * i3c_bus_normaluse_lock() for more details.
> + */
> +static void i3c_bus_downgrade_maintenance_lock(struct i3c_bus *bus)
> +{
> +	downgrade_write(&bus->lock);
> +}
>  static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
>  {
>  	return container_of(dev, struct i3c_master_controller, dev);
> @@ -341,6 +353,22 @@ static int i3c_device_probe(struct device *dev)
>  	return driver->probe(i3cdev);
>  }
>  
> +static int
> +i3c_master_enable_mr_events_locked(struct i3c_master_controller *master)
> +{
> +	if (!master->ops->enable_mr_events)
> +		return -ENOTSUPP;
> +
> +	return master->ops->enable_mr_events(master);
> +}
> +
> +static void i3c_master_disable_mr_events(struct i3c_master_controller *master)
> +{
> +	if (!master->ops->disable_mr_events)
> +		return;
> +
> +	master->ops->disable_mr_events(master);
> +}

Add new line.

It is not clear to me what you expect with these functions. Do you want 
to enable MR from all devices? Just some of them? How do you decide which 
secondary masters are allow earn the bus ownership?

>  static int i3c_device_remove(struct device *dev)
>  {
>  	struct i3c_device *i3cdev = dev_to_i3cdev(dev);
> @@ -462,6 +490,42 @@ static int i3c_bus_init(struct i3c_bus *i3cbus)
>  	return 0;
>  }
>  
> +static int
> +i3c_master_request_mastership_locked(struct i3c_master_controller *master)
> +{
> +	if (WARN_ON(master->init_done &&
> +	    !rwsem_is_locked(&master->bus.lock)))
> +		return -EINVAL;
> +
> +	if (!master->ops->request_mastership)
> +		return -ENOTSUPP;
> +
> +	return master->ops->request_mastership(master);
> +}
> +
> +static int i3c_master_owns_bus(struct i3c_master_controller *master)
> +{
> +	return (master->bus.cur_master == master->this);
> +}
> +
> +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master)
> +{
> +	int ret;
> +
> +	if (!i3c_master_owns_bus(master)) {
> +		i3c_bus_normaluse_unlock(&master->bus);
> +		i3c_bus_maintenance_lock(&master->bus);
> +
> +		ret = i3c_master_request_mastership_locked(master);
> +		if (ret) {
> +			i3c_bus_maintenance_unlock(&master->bus);
> +			return ret;
> +		}
> +		i3c_bus_downgrade_maintenance_lock(&master->bus);
> +	}
> +
> +	return 0;
> +}
>  static const char * const i3c_bus_mode_strings[] = {
>  	[I3C_BUS_MODE_PURE] = "pure",
>  	[I3C_BUS_MODE_MIXED_FAST] = "mixed-fast",
> @@ -636,6 +700,22 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
>  	return dev;
>  }
>  
> +static struct i2c_dev_desc *
> +i3c_master_alloc_i2c_dev_no_boardinfo(struct i3c_master_controller *master,
> +				      u16 addr, u8 lvr)

u8 addr.

> +{
> +	struct i2c_dev_desc *dev;
> +
> +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> +	if (!dev)
> +		return ERR_PTR(-ENOMEM);
> +
> +	dev->common.master = master;
> +	dev->addr = addr;
> +	dev->lvr = lvr;
> +
> +	return dev;
> +}
>  static void *i3c_ccc_cmd_dest_init(struct i3c_ccc_cmd_dest *dest, u8 addr,
>  				   u16 payloadlen)
>  {
> @@ -705,6 +785,8 @@ i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master,
>  	struct i2c_dev_desc *dev;
>  
>  	i3c_bus_for_each_i2cdev(&master->bus, dev) {
> +		if (!dev->boardinfo)
> +			continue;
>  		if (dev->boardinfo->base.addr == addr)
>  			return dev;
>  	}
> @@ -1478,7 +1560,8 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
>  		return;
>  
>  	i3c_bus_for_each_i3cdev(&master->bus, desc) {
> -		if (desc->dev || !desc->info.dyn_addr || desc == master->this)
> +		if (desc->dev || !desc->info.dyn_addr ||
> +		    desc == master->this || !desc->info.pid)
>  			continue;
>  
>  		desc->dev = kzalloc(sizeof(*desc->dev), GFP_KERNEL);
> @@ -1504,6 +1587,69 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
>  	}
>  }
>  
> +static struct i2c_dev_boardinfo *
> +i3c_master_find_i2c_boardinfo(const struct i3c_master_controller *master,
> +			      u16 addr, u8 lvr)

Same.

> +{
> +	struct i2c_dev_boardinfo *i2cboardinfo;
> +
> +	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
> +		if (i2cboardinfo->base.addr == addr &&
> +		    i2cboardinfo->lvr == lvr)
> +			return i2cboardinfo;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void
> +i3c_master_register_new_i2c_devs(struct i3c_master_controller *master)
> +{
> +	struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
> +	struct i2c_dev_desc *i2cdev;
> +
> +	if (!master->init_done)
> +		return;
> +
> +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> +
> +		if (i2cdev->dev)
> +			continue;
> +
> +		if (!i2cdev->boardinfo)
> +			continue;
> +
> +		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
> +	}
> +}
> +
> +static int i3c_master_get_accmst_locked(struct i3c_master_controller *master,
> +					u8 addr)
> +{
> +	struct i3c_ccc_getaccmst *accmst;
> +	struct i3c_ccc_cmd_dest dest;
> +	struct i3c_ccc_cmd cmd;
> +	int ret;
> +
> +	accmst = i3c_ccc_cmd_dest_init(&dest, addr, sizeof(*accmst));
> +	if (!accmst)
> +		return -ENOMEM;
> +
> +	i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETACCMST, &dest, 1);
> +
> +	ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
> +	if (ret)
> +		goto out;
> +
> +	if (dest.payload.len != sizeof(*accmst))
> +		ret = -EIO;
> +
> +out:
> +	i3c_ccc_cmd_dest_cleanup(&dest);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(i3c_master_get_accmst_locked);
>  /**
>   * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
>   * @master: master doing the DAA
> @@ -1548,10 +1694,6 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
>  	if (!i3c_bus_dev_addr_is_avail(&master->bus, info->dyn_addr))
>  		return -EINVAL;
>  
> -	if (I3C_BCR_DEVICE_ROLE(info->bcr) == I3C_BCR_I3C_MASTER &&
> -	    master->secondary)
> -		return -EINVAL;
> -
>  	if (master->this)
>  		return -EINVAL;
>  
> @@ -1560,7 +1702,8 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
>  		return PTR_ERR(i3cdev);
>  
>  	master->this = i3cdev;
> -	master->bus.cur_master = master->this;
> +	if (!secondary)
> +		master->bus.cur_master = master->this;
>  
>  	ret = i3c_master_attach_i3c_dev(master, i3cdev);
>  	if (ret)
> @@ -1601,37 +1744,7 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
>  	}
>  }
>  
> -/**
> - * i3c_master_bus_init() - initialize an I3C bus
> - * @master: main master initializing the bus
> - *
> - * This function is following all initialisation steps described in the I3C
> - * specification:
> - *
> - * 1. Attach I2C and statically defined I3C devs to the master so that the
> - *    master can fill its internal device table appropriately
> - *
> - * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
> - *    the master controller. That's usually where the bus mode is selected
> - *    (pure bus or mixed fast/slow bus)
> - *
> - * 3. Instruct all devices on the bus to drop their dynamic address. This is
> - *    particularly important when the bus was previously configured by someone
> - *    else (for example the bootloader)
> - *
> - * 4. Disable all slave events.
> - *
> - * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
> - *    devices that have a static address
> - *
> - * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
> - *    remaining I3C devices
> - *
> - * Once this is done, all I3C and I2C devices should be usable.
> - *
> - * Return: a 0 in case of success, an negative error code otherwise.
> - */
> -static int i3c_master_bus_init(struct i3c_master_controller *master)
> +static int i3c_master_attach_static_devs(struct i3c_master_controller *master)
>  {
>  	enum i3c_addr_slot_status status;
>  	struct i2c_dev_boardinfo *i2cboardinfo;
> @@ -1640,32 +1753,24 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
>  	struct i2c_dev_desc *i2cdev;
>  	int ret;
>  
> -	/*
> -	 * First attach all devices with static definitions provided by the
> -	 * FW.
> -	 */
>  	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
>  		status = i3c_bus_get_addr_slot_status(&master->bus,
>  						      i2cboardinfo->base.addr);
> -		if (status != I3C_ADDR_SLOT_FREE) {
> -			ret = -EBUSY;
> -			goto err_detach_devs;
> -		}
> +		if (status != I3C_ADDR_SLOT_FREE)
> +			return -EBUSY;
>  
>  		i3c_bus_set_addr_slot_status(&master->bus,
>  					     i2cboardinfo->base.addr,
>  					     I3C_ADDR_SLOT_I2C_DEV);
>  
>  		i2cdev = i3c_master_alloc_i2c_dev(master, i2cboardinfo);
> -		if (IS_ERR(i2cdev)) {
> -			ret = PTR_ERR(i2cdev);
> -			goto err_detach_devs;
> -		}
> +		if (IS_ERR(i2cdev))
> +			return PTR_ERR(i2cdev);
>  
>  		ret = i3c_master_attach_i2c_dev(master, i2cdev);
>  		if (ret) {
>  			i3c_master_free_i2c_dev(i2cdev);
> -			goto err_detach_devs;
> +			return ret;
>  		}
>  	}
>  	list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) {
> @@ -1676,27 +1781,68 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
>  		if (i3cboardinfo->init_dyn_addr) {
>  			status = i3c_bus_get_addr_slot_status(&master->bus,
>  						i3cboardinfo->init_dyn_addr);
> -			if (status != I3C_ADDR_SLOT_FREE) {
> -				ret = -EBUSY;
> -				goto err_detach_devs;
> -			}
> +			if (status != I3C_ADDR_SLOT_FREE)
> +				return -EBUSY;
>  		}
>  
>  		i3cdev = i3c_master_alloc_i3c_dev(master, &info);
> -		if (IS_ERR(i3cdev)) {
> -			ret = PTR_ERR(i3cdev);
> -			goto err_detach_devs;
> -		}
> +		if (IS_ERR(i3cdev))
> +			return PTR_ERR(i3cdev);
>  
>  		i3cdev->boardinfo = i3cboardinfo;
>  
>  		ret = i3c_master_attach_i3c_dev(master, i3cdev);
>  		if (ret) {
>  			i3c_master_free_i3c_dev(i3cdev);
> -			goto err_detach_devs;
> +			return ret;
>  		}
>  	}
>  
> +	return 0;
> +}
> +
> +/**
> + * i3c_master_bus_init() - initialize an I3C bus
> + * @master: main master initializing the bus
> + *
> + * This function is following all initialisation steps described in the I3C
> + * specification:
> + *
> + * 1. Attach I2C and statically defined I3C devs to the master so that the
> + *    master can fill its internal device table appropriately
> + *
> + * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
> + *    the master controller. That's usually where the bus mode is selected
> + *    (pure bus or mixed fast/slow bus)
> + *
> + * 3. Instruct all devices on the bus to drop their dynamic address. This is
> + *    particularly important when the bus was previously configured by someone
> + *    else (for example the bootloader)
> + *
> + * 4. Disable all slave events.
> + *
> + * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
> + *    devices that have a static address
> + *
> + * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
> + *    remaining I3C devices
> + *
> + * Once this is done, all I3C and I2C devices should be usable.
> + *
> + * Return: a 0 in case of success, an negative error code otherwise.
> + */
> +static int i3c_master_bus_init(struct i3c_master_controller *master)
> +{
> +	struct i3c_dev_desc *i3cdev;
> +	int ret;
> +
> +	/*
> +	 * First attach all devices with static definitions provided by the
> +	 * FW.
> +	 */
> +	ret = i3c_master_attach_static_devs(master);
> +	if (ret)
> +		goto err_detach_devs;
>  	/*
>  	 * Now execute the controller specific ->bus_init() routine, which
>  	 * might configure its internal logic to match the bus limitations.
> @@ -1780,45 +1926,76 @@ i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev)
>  }
>  
>  /**
> - * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> - * @master: master used to send frames on the bus
> - * @addr: I3C slave dynamic address assigned to the device
> + * i3c_master_add_i2c_dev_locked() - add an I2C slave to the bus
> + * @master: master used to register I2C device
> + * @addr: I2C device address
> + * @lvr: legacy virtual register value
>   *
> - * This function is instantiating an I3C device object and adding it to the
> - * I3C device list. All device information are automatically retrieved using
> - * standard CCC commands.
> - *
> - * The I3C device object is returned in case the master wants to attach
> - * private data to it using i3c_dev_set_master_data().
> + * This function is instantiating an I2C device object and adding it to the
> + * I2C device list.
>   *
>   * This function must be called with the bus lock held in write mode.
>   *
>   * Return: a 0 in case of success, an negative error code otherwise.
>   */
> -int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> -				  u8 addr)
> +int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
> +				  u16 addr, u8 lvr)
>  {
> -	struct i3c_device_info info = { .dyn_addr = addr };
> -	struct i3c_dev_desc *newdev, *olddev;
> -	u8 old_dyn_addr = addr, expected_dyn_addr;
> -	struct i3c_ibi_setup ibireq = { };
> -	bool enable_ibi = false;
> +	enum i3c_addr_slot_status status;
> +	struct i2c_dev_desc *i2cdev;
>  	int ret;
>  
>  	if (!master)
>  		return -EINVAL;
>  
> -	newdev = i3c_master_alloc_i3c_dev(master, &info);
> -	if (IS_ERR(newdev))
> -		return PTR_ERR(newdev);
> +	status = i3c_bus_get_addr_slot_status(&master->bus,
> +					      addr);
> +	if (status != I3C_ADDR_SLOT_FREE)
> +		return -EBUSY;
>  
> -	ret = i3c_master_attach_i3c_dev(master, newdev);
> -	if (ret)
> +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> +				     I3C_ADDR_SLOT_I2C_DEV);
> +
> +	i2cdev = i3c_master_alloc_i2c_dev_no_boardinfo(master, addr, lvr);
> +
> +	if (IS_ERR(i2cdev)) {
> +		ret = PTR_ERR(i2cdev);
> +		goto err_free_dev;
> +	}
> +
> +	i2cdev->boardinfo = i3c_master_find_i2c_boardinfo(master, addr, lvr);
> +
> +	ret = i3c_master_attach_i2c_dev(master, i2cdev);
> +
> +	if (ret) {
> +		ret = PTR_ERR(i2cdev);
>  		goto err_free_dev;
> +	}
> +
> +	return 0;
> +
> +err_free_dev:
> +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> +				     I3C_ADDR_SLOT_FREE);
> +	i3c_master_free_i2c_dev(i2cdev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(i3c_master_add_i2c_dev_locked);
> +
> +static int
> +i3c_master_retrieve_info_and_reuse(struct i3c_master_controller *master,
> +				   struct i3c_dev_desc *newdev)
> +{
> +	struct i3c_dev_desc *olddev;
> +	u8 old_dyn_addr = newdev->info.dyn_addr, expected_dyn_addr;
> +	struct i3c_ibi_setup ibireq = { };
> +	bool enable_ibi = false;
> +	int ret;
>  
>  	ret = i3c_master_retrieve_dev_info(newdev);
>  	if (ret)
> -		goto err_detach_dev;
> +		return ret;
>  
>  	olddev = i3c_master_search_i3c_dev_duplicate(newdev);
>  	if (olddev) {
> @@ -1857,7 +2034,7 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
>  
>  	ret = i3c_master_reattach_i3c_dev(newdev, old_dyn_addr);
>  	if (ret)
> -		goto err_detach_dev;
> +		return ret;
>  
>  	/*
>  	 * Depending on our previous state, the expected dynamic address might
> @@ -1920,6 +2097,50 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
>  	}
>  
>  	return 0;
> +}
> +
> +/**
> + * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> + * @master: master used to send frames on the bus
> + * @addr: I3C slave dynamic address assigned to the device
> + *
> + * This function is instantiating an I3C device object and adding it to the
> + * I3C device list. All device information are automatically retrieved using
> + * standard CCC commands.
> + *
> + * The I3C device object is returned in case the master wants to attach
> + * private data to it using i3c_dev_set_master_data().
> + *
> + * This function must be called with the bus lock held in write mode.
> + *
> + * Return: a 0 in case of success, an negative error code otherwise.
> + */
> +int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> +				  u8 addr)
> +{
> +	struct i3c_device_info info = { .dyn_addr = addr };
> +	struct i3c_dev_desc *newdev;
> +	int ret;
> +
> +	if (!master)
> +		return -EINVAL;
> +
> +	newdev = i3c_master_alloc_i3c_dev(master, &info);
> +	if (IS_ERR(newdev))
> +		return PTR_ERR(newdev);
> +
> +	ret = i3c_master_attach_i3c_dev(master, newdev);
> +	if (ret)
> +		goto err_free_dev;
> +
> +	if (i3c_master_owns_bus(master)) {
> +		ret = i3c_master_retrieve_info_and_reuse(master, newdev);
> +		if (ret)
> +			goto err_detach_dev;
> +	} else
> +		master->want_to_acquire_bus = true;
> +
> +	return 0;
>  
>  err_detach_dev:
>  	if (newdev->dev && newdev->dev->desc)
> @@ -2101,11 +2322,15 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
>  	}
>  
>  	i3c_bus_normaluse_lock(&master->bus);
> +	ret = i3c_master_acquire_bus_ownership(master);
> +	if (ret)
> +		goto err_unlock_bus;
>  	dev = i3c_master_find_i2c_dev_by_addr(master, addr);
>  	if (!dev)
>  		ret = -ENOENT;
>  	else
>  		ret = master->ops->i2c_xfers(dev, xfers, nxfers);
> +err_unlock_bus:
>  	i3c_bus_normaluse_unlock(&master->bus);
>  
>  	return ret ? ret : nxfers;
> @@ -2144,9 +2369,12 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
>  	 * We silently ignore failures here. The bus should keep working
>  	 * correctly even if one or more i2c devices are not registered.
>  	 */
> -	i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
> +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> +		if (!i2cdev->boardinfo)
> +			continue;
>  		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
>  
> +	}
>  	return 0;
>  }
>  
> @@ -2385,9 +2613,76 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
>  	     !ops->recycle_ibi_slot))
>  		return -EINVAL;
>  
> +	/*
> +	 * If mastership request is supported, we also need hooks to control
> +	 * when mastership request can occur by enabling/disabling the event.
> +	 */
> +	if (ops->request_mastership &&
> +	    (!ops->enable_mr_events || !ops->disable_mr_events))
> +		return -EINVAL;
>  	return 0;
>  }
>  
> +static void i3c_master_register_new_devs(struct i3c_master_controller *master)
> +{
> +	/*
> +	 * We can register devices received from master by DEFSLVS.
> +	 */
> +	i3c_bus_normaluse_lock(&master->bus);
> +	i3c_master_register_new_i3c_devs(master);
> +	i3c_master_register_new_i2c_devs(master);
> +	i3c_bus_normaluse_unlock(&master->bus);
> +}
> +
> +/**
> + * i3c_master_bus_takeover() - register new I3C devices on bus takeover
> + * @master: master used to send frames on the bus
> + *
> + * This function is useful when devices were not added
> + * during initialization or when new device joined the bus
> + * which wasn't under our control.
> + */
> +void i3c_master_bus_takeover(struct i3c_master_controller *master)
> +{
> +	struct i3c_dev_desc *i3cdev, *i3ctmp;
> +	int ret;
> +
> +	master->want_to_acquire_bus = false;

Can you explain the usage of this variable?

> +
> +	if (!master->init_done)
> +		return;
> +
> +	i3c_bus_maintenance_lock(&master->bus);
> +	master->ops->populate_bus(master);
> +
> +	list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c,
> +				 common.node) {
> +		if (i3cdev->info.pid)
> +			continue;
> +
> +		ret = i3c_master_retrieve_info_and_reuse(master, i3cdev);
> +		if (ret) {
> +			if (i3cdev->dev && i3cdev->dev->desc)
> +				i3cdev->dev->desc = NULL;
> +
> +			i3c_master_detach_i3c_dev(i3cdev);
> +		}
> +	}
> +
> +	/*
> +	 * If current master finished bus initialization properly, we can
> +	 * enable Mastership event.
> +	 */
> +	ret = i3c_master_enable_mr_events_locked(master);
> +	if (ret)
> +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> +
> +	i3c_bus_maintenance_unlock(&master->bus);
> +
> +	i3c_master_register_new_devs(master);
> +}
> +EXPORT_SYMBOL_GPL(i3c_master_bus_takeover);
> +
>  /**
>   * i3c_master_init() - initializes all the structures required by I3C master
>   * @master: master used to send frames on the bus
> @@ -2417,9 +2712,6 @@ int i3c_master_init(struct i3c_master_controller *master,
>  	struct i2c_dev_boardinfo *i2cbi;
>  	int ret;
>  
> -	/* We do not support secondary masters yet. */
> -	if (secondary)
> -		return -ENOTSUPP;
>  
>  	ret = i3c_master_check_ops(ops);
>  	if (ret)
> @@ -2432,6 +2724,7 @@ int i3c_master_init(struct i3c_master_controller *master,
>  	master->dev.release = i3c_masterdev_release;
>  	master->ops = ops;
>  	master->secondary = secondary;
> +	master->want_to_acquire_bus = secondary;
>  	INIT_LIST_HEAD(&master->boardinfo.i2c);
>  	INIT_LIST_HEAD(&master->boardinfo.i3c);
>  
> @@ -2488,6 +2781,92 @@ void i3c_master_cleanup(struct i3c_master_controller *master)
>  EXPORT_SYMBOL_GPL(i3c_master_cleanup);
>  
>  /**
> + * i3c_secondary_master_register() - register an secondary I3C master
> + * @master: master used to send frames on the bus
> + * @info: master info, describes this device
> + *
> + * This function takes care of everything for you:
> + *
> + * - updates this master info
> + * - registers the I2C adapter
> + * - if possible, populates the bus with devices received by DEFSLVS
> + *   command
> + *
> + * Return: 0 in case of success, a negative error code otherwise.
> + */
> +int i3c_secondary_master_register(struct i3c_master_controller *master,
> +				  struct i3c_device_info *info)
> +{
> +	int ret;
> +
> +	ret = i3c_master_set_info(master, info, master->secondary);
> +	if (ret)
> +		return ret;
> +
> +	ret = master->ops->bus_init(master);
> +	if (ret)
> +		return ret;

At this point you don't have enough information to do the bus 
initialization.

> +
> +	ret = device_add(&master->dev);
> +	if (ret)
> +		return -1;
> +
> +	/*
> +	 * Expose our I3C bus as an I2C adapter so that I2C devices are exposed
> +	 * through the I2C subsystem.
> +	 */
> +	ret = i3c_master_i2c_adapter_init(master);
> +	if (ret)
> +		goto err_del_dev;
> +
> +	i3c_bus_maintenance_lock(&master->bus);
> +	/*
> +	 * If possible, request mastership and try to populate the bus.
> +	 */
> +	ret = i3c_master_request_mastership_locked(master);
> +	if (ret)
> +		dev_warn(&master->dev,
> +			 "Mastership failed at init time (ret = %i)", ret);
> +
> +	/*
> +	 * No matter if mastership takeover passed or not, add partialy
> +	 * discovered devices. We can register them when ENEC(MR) is enabled.
> +	 */
> +	master->ops->populate_bus(master);
> +
> +	i3c_bus_maintenance_unlock(&master->bus);
> +
> +	/*
> +	 * We're done initializing the bus and the controller, we can now
> +	 * register I3C devices obtained by DEFSLVS.
> +	 */
> +	master->init_done = true;
> +	i3c_master_register_new_devs(master);
> +
> +	/*
> +	 * If we are owning the bus, enable ENEC(MR) to let other masters
> +	 * initialize their bus.
> +	 */
> +	if (i3c_master_owns_bus(master)) {
> +		i3c_bus_maintenance_lock(&master->bus);
> +		ret = i3c_master_enable_mr_events_locked(master);
> +		i3c_bus_maintenance_unlock(&master->bus);
> +		if (ret)
> +			dev_warn(&master->dev,
> +				 "ENEC(MR) failed (ret = %i)", ret);
> +	}
> +
> +
> +	return 0;
> +
> +err_del_dev:
> +	device_del(&master->dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(i3c_secondary_master_register);
> +
> +/**
>   * i3c_master_register() - register an primary I3C master
>   * @master: master used to send frames on the bus
>   * @info: master info, describes this device
> @@ -2509,7 +2888,6 @@ int i3c_master_register(struct i3c_master_controller *master,
>  	ret = i3c_master_set_info(master, info, master->secondary);
>  	if (ret)
>  		return ret;
> -
>  	ret = i3c_master_bus_init(master);
>  	if (ret)
>  		return ret;
> @@ -2535,6 +2913,16 @@ int i3c_master_register(struct i3c_master_controller *master,
>  	i3c_master_register_new_i3c_devs(master);
>  	i3c_bus_normaluse_unlock(&master->bus);
>  
> +	/*
> +	 * Enable ENEC(MR) and let other masters request mastership
> +	 * and initialize their bus.
> +	 */
> +	i3c_bus_maintenance_lock(&master->bus);
> +	ret = i3c_master_enable_mr_events_locked(master);
> +	i3c_bus_maintenance_unlock(&master->bus);
> +	if (ret)
> +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> +
>  	return 0;
>  
>  err_del_dev:
> @@ -2548,6 +2936,29 @@ int i3c_master_register(struct i3c_master_controller *master,
>  EXPORT_SYMBOL_GPL(i3c_master_register);
>  
>  /**
> + * i3c_master_mastership_ack() - acknowledges bus takeover.
> + * @master: master used to send frames on the bus
> + * @addr: I3C device address
> + *
> + * This function acknowledges bus takeover.
> + *
> + * Return: 0 in case of success, a negative error code otherwise.
> + */
> +int i3c_master_mastership_ack(struct i3c_master_controller *master,
> +			      u8 addr)
> +{
> +	int ret;
> +
> +	i3c_bus_maintenance_lock(&master->bus);
> +	ret = i3c_master_get_accmst_locked(master, addr);
> +	i3c_bus_maintenance_unlock(&master->bus);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(i3c_master_mastership_ack);
> +
> +
> +/**
>   * i3c_master_unregister() - unregister an I3C master
>   * @master: master used to send frames on the bus
>   *
> @@ -2557,6 +2968,9 @@ EXPORT_SYMBOL_GPL(i3c_master_register);
>   */
>  int i3c_master_unregister(struct i3c_master_controller *master)
>  {
> +	i3c_bus_maintenance_lock(&master->bus);
> +	i3c_master_disable_mr_events(master);
> +	i3c_bus_maintenance_unlock(&master->bus);
>  	i3c_master_i2c_adapter_cleanup(master);
>  	i3c_master_unregister_i3c_devs(master);
>  	i3c_master_bus_cleanup(master);
> diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
> index e089771..6ac9b46 100644
> --- a/include/linux/i3c/master.h
> +++ b/include/linux/i3c/master.h
> @@ -421,6 +421,26 @@ struct i3c_bus {
>   *		      for a future IBI
>   *		      This method is mandatory only if ->request_ibi is not
>   *		      NULL.
> + * @request_mastership: requests bus mastership. Mastership is requested
> + *                      automatically when device driver wants to transfer
> + *                      data using a master that does not currently
> + *                      owns the bus.
> + * @enable_mr_events: enable the Mastership event. Master driver can prepare
> + *                    its internal state to be ready for incoming mastership
> + *                    requests and then should send ENEC(MR) command to let
> + *                    other masters take control over the bus.
> + * @disable_mr_events: disable the Mastership event. Master driver should
> + *                     immediately send DISEC(MR) command and can perform other
> + *                     operations. For example, recycle IBI slot if used before
> + *                     for MR event.
> + * @populate_pus: populates the bus. Called after bus takeover. Secondary
> + *                master can't perform DAA procedure. This function allows to
> + *                update devices received from previous bus owner in DEFSLVS
> + *                command. Useful also when new device joins the bus controlled
> + *                by secondary master, main master will be able to add
> + *                this device after mastership takeover. Driver should also
> + *		  update bus mode when I2C device is on the bus.
> + *
>   */
>  struct i3c_master_controller_ops {
>  	int (*bus_init)(struct i3c_master_controller *master);
> @@ -447,6 +467,10 @@ struct i3c_master_controller_ops {
>  	int (*disable_ibi)(struct i3c_dev_desc *dev);
>  	void (*recycle_ibi_slot)(struct i3c_dev_desc *dev,
>  				 struct i3c_ibi_slot *slot);
> +	int (*request_mastership)(struct i3c_master_controller *master);
> +	int (*enable_mr_events)(struct i3c_master_controller *master);
> +	int (*disable_mr_events)(struct i3c_master_controller *master);
> +	int (*populate_bus)(struct i3c_master_controller *master);
>  };
>  
>  /**
> @@ -488,6 +512,7 @@ struct i3c_master_controller {
>  	} boardinfo;
>  	struct i3c_bus bus;
>  	struct workqueue_struct *wq;
> +	bool want_to_acquire_bus;
>  };
>  
>  /**
> @@ -526,6 +551,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master);
>  int i3c_master_get_free_addr(struct i3c_master_controller *master,
>  			     u8 start_addr);
>  
> +int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
> +				  u16 addr, u8 lvr);
>  int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
>  				  u8 addr);
>  int i3c_master_do_daa(struct i3c_master_controller *master);
> @@ -535,9 +562,14 @@ int i3c_master_init(struct i3c_master_controller *master,
>  		    const struct i3c_master_controller_ops *ops,
>  		    bool secondary);
>  void i3c_master_cleanup(struct i3c_master_controller *master);
> +int i3c_secondary_master_register(struct i3c_master_controller *master,
> +				  struct i3c_device_info *info);
>  int i3c_master_register(struct i3c_master_controller *master,
>  			struct i3c_device_info *info);
>  int i3c_master_unregister(struct i3c_master_controller *master);
> +int i3c_master_mastership_ack(struct i3c_master_controller *master,
> +			      u8 addr);
> +void i3c_master_bus_takeover(struct i3c_master_controller *master);
>  int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode);
>  
>  /**
> @@ -648,7 +680,5 @@ void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot);
>  
>  struct i3c_ibi_slot *i3c_master_get_free_ibi_slot(struct i3c_dev_desc *dev);
>  
> -void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> -void i3c_bus_maintenance_unlock(struct i3c_bus *bus);
>  
>  #endif /* I3C_MASTER_H */
> -- 
> 2.4.5

In generally I found this intrusive for the current eco system.

I propose the following:
1 - Keep the function i3c_master_register() as is and go out before 
i3c_master_bus_init() if secondary master.
@Boris Brezillon is it possible to replace device_initialize() device_add() with device_register()?

2 - When received DEFSLVS commands add devices to a link list like 
boardinfo.
  Get bus ownership if there is DEFSLVS to add or secondary master not 
initialized. 

3 - When received ENEC MR
  Get bus ownership if there is DEFSLVS to add or secondary master not 
initialized.

4 - When secondary master became current master.
  Attach new devices to the host controller and retrieve device info 
(same logic as in i3c_master_add_i3c_dev_locked).

With this approach on HC side you just need to add the secondary master 
stuff without changing the current code and leave for the subsystem the 
responsible to manage all these secondary master task.

Let me know if this works for you.


Best regards,
Vitor Soares

_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem
  2019-07-10 18:04   ` Vitor Soares
@ 2019-07-11  5:28     ` Przemyslaw Gaj
  2019-07-11 10:11       ` Vitor Soares
  0 siblings, 1 reply; 21+ messages in thread
From: Przemyslaw Gaj @ 2019-07-11  5:28 UTC (permalink / raw)
  To: Vitor Soares; +Cc: linux-i3c, agolec, rafalc, bbrezillon

Hi Vitor,

The 07/10/2019 18:04, Vitor Soares wrote:
> EXTERNAL MAIL
> 
> 
> From: Przemyslaw Gaj <pgaj@cadence.com>
> Date: Sat, Jun 22, 2019 at 21:55:02
> 
> > This patch adds support for mastership request to I3C subsystem.
> > 
> > Mastership event is enabled globally.
> > 
> > Mastership is requested automatically when device driver
> > tries to transfer data using master controller in slave mode.
> > 
> > There is still some limitation:
> > - I2C devices are registered on secondary master side if boardinfo
> > entry matching the info transmitted through the DEFSLVS frame.
> > 
> > Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
> > 
> > ---
> > 
> > Main changes between v4 and v5:
> > - Add function to test if master owns the bus
> > - Add i3c_secondary_master_register() function
> > - Add populate_bus() hook to populate the bus after mastership takeover
> 
> For me this task is for the sub-system not the host controller.
> 

I'm not sure where device information is stored in DW controller but in CDNS
controller DEFSLVS frame is processed in the device and the only thing I got is
information that DEFSLVS came in. I need to inform subsystem that there are new
device (if any). I remember we talkad about that already, you have access to
DEFSLVS information directly, correct?

> > - Rework device information retrieval to allow adding partialy discovered
> > devices
> > 
> > Main changes between v3 and v4:
> > - Add i3c_master_acquire_bus_ownership to acquire the bus
> > - Refactored the code
> > 
> > Main changes between v2 and v3:
> > - Add i3c_bus_downgrade_maintenance_lock() for downgrading the bus
> > lock from maintenance to normal use
> > - Add additional fields to i2c_dev_desc for DEFSLVS purpose (addr, lvr)
> > - Add i3c_master_register_new_i2c_devs() function to register I2C devices
> > - Reworked I2C devices registration on secondary master side
> > 
> > Changes in v2:
> > - Add mastership disable event hook
> > - Changed name of mastership enable event hook
> > - Add function to test if master owns the bus
> > - Removed op_mode
> > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > pass full i3c_device_info
> > - Changed name of mastership enable event hook
> > - Add function to test if master owns the bus
> > - Removed op_mode
> > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > pass full i3c_device_info
> > - Removed redundant DEFSLVS command before GETACCMST
> > - Add i3c_master_bus_takeover function. There is a need to lock
> > the bus before adding devices and no matter of the controller
> > devices have to be added after mastership takeover.
> > - Add device registration during initialization on secondary master
> > side. Devices received by DEFSLVS (if occured). If not, device
> > initialization is deffered untill next mastership request.
> > ---
> >  drivers/i3c/device.c       |  26 ++
> >  drivers/i3c/internals.h    |   4 +
> >  drivers/i3c/master.c       | 588 ++++++++++++++++++++++++++++++++++++++-------
> >  include/linux/i3c/master.h |  34 ++-
> >  4 files changed, 563 insertions(+), 89 deletions(-)
> > 
> > diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
> > index 69cc040..b60f637 100644
> > --- a/drivers/i3c/device.c
> > +++ b/drivers/i3c/device.c
> > @@ -43,7 +43,13 @@ int i3c_device_do_priv_xfers(struct i3c_device *dev,
> >  	}
> >  
> >  	i3c_bus_normaluse_lock(dev->bus);
> > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > +	if (ret)
> > +		goto err_unlock_bus;
> > +
> >  	ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
> > +
> > +err_unlock_bus:
> >  	i3c_bus_normaluse_unlock(dev->bus);
> >  
> >  	return ret;
> > @@ -114,11 +120,17 @@ int i3c_device_enable_ibi(struct i3c_device *dev)
> >  	int ret = -ENOENT;
> >  
> >  	i3c_bus_normaluse_lock(dev->bus);
> > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > +	if (ret)
> > +		goto err_unlock_bus;
> > +
> >  	if (dev->desc) {
> >  		mutex_lock(&dev->desc->ibi_lock);
> >  		ret = i3c_dev_enable_ibi_locked(dev->desc);
> >  		mutex_unlock(&dev->desc->ibi_lock);
> >  	}
> > +
> > +err_unlock_bus:
> >  	i3c_bus_normaluse_unlock(dev->bus);
> >  
> >  	return ret;
> > @@ -145,11 +157,17 @@ int i3c_device_request_ibi(struct i3c_device *dev,
> >  		return -EINVAL;
> >  
> >  	i3c_bus_normaluse_lock(dev->bus);
> > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > +	if (ret)
> > +		goto err_unlock_bus;
> > +
> >  	if (dev->desc) {
> >  		mutex_lock(&dev->desc->ibi_lock);
> >  		ret = i3c_dev_request_ibi_locked(dev->desc, req);
> >  		mutex_unlock(&dev->desc->ibi_lock);
> >  	}
> > +
> > +err_unlock_bus:
> >  	i3c_bus_normaluse_unlock(dev->bus);
> >  
> >  	return ret;
> > @@ -166,12 +184,20 @@ EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
> >   */
> >  void i3c_device_free_ibi(struct i3c_device *dev)
> >  {
> > +	int ret;
> > +
> >  	i3c_bus_normaluse_lock(dev->bus);
> > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > +	if (ret)
> > +		goto err_unlock_bus;
> > +
> >  	if (dev->desc) {
> >  		mutex_lock(&dev->desc->ibi_lock);
> >  		i3c_dev_free_ibi_locked(dev->desc);
> >  		mutex_unlock(&dev->desc->ibi_lock);
> >  	}
> > +
> > +err_unlock_bus:
> >  	i3c_bus_normaluse_unlock(dev->bus);
> >  }
> >  EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
> > diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
> > index 86b7b44..cdfc5bf 100644
> > --- a/drivers/i3c/internals.h
> > +++ b/drivers/i3c/internals.h
> > @@ -14,6 +14,10 @@ extern struct bus_type i3c_bus_type;
> >  
> >  void i3c_bus_normaluse_lock(struct i3c_bus *bus);
> >  void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
> > +void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> > +void i3c_bus_maintenance_unlock(struct i3c_bus *bus);
> 
> These function are static.
> 

I forgot to revert that change to previous state.

> > +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master);
> > +
> 
> What do you think to pass this logic to master.c?
> 

Isn't it there?

> >  
> >  int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
> >  				 struct i3c_priv_xfer *xfers,
> > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> > index cbace14..3b44e66 100644
> > --- a/drivers/i3c/master.c
> > +++ b/drivers/i3c/master.c
> > @@ -93,6 +93,18 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
> >  	up_read(&bus->lock);
> >  }
> >  
> > +/*
> > + * i3c_bus_downgrade_maintenance_lock - Downgrade the bus lock to normal
> > + * operation
> > + *
> > + * Should be called when a maintenance operation is done and normal
> > + * operation is planned. See i3c_bus_maintenance_lock() and
> > + * i3c_bus_normaluse_lock() for more details.
> > + */
> > +static void i3c_bus_downgrade_maintenance_lock(struct i3c_bus *bus)
> > +{
> > +	downgrade_write(&bus->lock);
> > +}
> >  static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
> >  {
> >  	return container_of(dev, struct i3c_master_controller, dev);
> > @@ -341,6 +353,22 @@ static int i3c_device_probe(struct device *dev)
> >  	return driver->probe(i3cdev);
> >  }
> >  
> > +static int
> > +i3c_master_enable_mr_events_locked(struct i3c_master_controller *master)
> > +{
> > +	if (!master->ops->enable_mr_events)
> > +		return -ENOTSUPP;
> > +
> > +	return master->ops->enable_mr_events(master);
> > +}
> > +
> > +static void i3c_master_disable_mr_events(struct i3c_master_controller *master)
> > +{
> > +	if (!master->ops->disable_mr_events)
> > +		return;
> > +
> > +	master->ops->disable_mr_events(master);
> > +}
> 
> Add new line.
> 
> It is not clear to me what you expect with these functions. Do you want 
> to enable MR from all devices? Just some of them? How do you decide which 
> secondary masters are allow earn the bus ownership?
> 

We discussed this also. For now, we enable ENEC for all masters on the bus, we
can change it later if needed. Also, priority level is encoded in slave address
so current master will give the control to the master with lower address first.
It shouldn't be a problem.

> >  static int i3c_device_remove(struct device *dev)
> >  {
> >  	struct i3c_device *i3cdev = dev_to_i3cdev(dev);
> > @@ -462,6 +490,42 @@ static int i3c_bus_init(struct i3c_bus *i3cbus)
> >  	return 0;
> >  }
> >  
> > +static int
> > +i3c_master_request_mastership_locked(struct i3c_master_controller *master)
> > +{
> > +	if (WARN_ON(master->init_done &&
> > +	    !rwsem_is_locked(&master->bus.lock)))
> > +		return -EINVAL;
> > +
> > +	if (!master->ops->request_mastership)
> > +		return -ENOTSUPP;
> > +
> > +	return master->ops->request_mastership(master);
> > +}
> > +
> > +static int i3c_master_owns_bus(struct i3c_master_controller *master)
> > +{
> > +	return (master->bus.cur_master == master->this);
> > +}
> > +
> > +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master)
> > +{
> > +	int ret;
> > +
> > +	if (!i3c_master_owns_bus(master)) {
> > +		i3c_bus_normaluse_unlock(&master->bus);
> > +		i3c_bus_maintenance_lock(&master->bus);
> > +
> > +		ret = i3c_master_request_mastership_locked(master);
> > +		if (ret) {
> > +			i3c_bus_maintenance_unlock(&master->bus);
> > +			return ret;
> > +		}
> > +		i3c_bus_downgrade_maintenance_lock(&master->bus);
> > +	}
> > +
> > +	return 0;
> > +}
> >  static const char * const i3c_bus_mode_strings[] = {
> >  	[I3C_BUS_MODE_PURE] = "pure",
> >  	[I3C_BUS_MODE_MIXED_FAST] = "mixed-fast",
> > @@ -636,6 +700,22 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
> >  	return dev;
> >  }
> >  
> > +static struct i2c_dev_desc *
> > +i3c_master_alloc_i2c_dev_no_boardinfo(struct i3c_master_controller *master,
> > +				      u16 addr, u8 lvr)
> 
> u8 addr.
> 

Originaly I2C address is u16 but we can change it as we know DEFSLVS does not
support 10bit addresses.

> > +{
> > +	struct i2c_dev_desc *dev;
> > +
> > +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> > +	if (!dev)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	dev->common.master = master;
> > +	dev->addr = addr;
> > +	dev->lvr = lvr;
> > +
> > +	return dev;
> > +}
> >  static void *i3c_ccc_cmd_dest_init(struct i3c_ccc_cmd_dest *dest, u8 addr,
> >  				   u16 payloadlen)
> >  {
> > @@ -705,6 +785,8 @@ i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master,
> >  	struct i2c_dev_desc *dev;
> >  
> >  	i3c_bus_for_each_i2cdev(&master->bus, dev) {
> > +		if (!dev->boardinfo)
> > +			continue;
> >  		if (dev->boardinfo->base.addr == addr)
> >  			return dev;
> >  	}
> > @@ -1478,7 +1560,8 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
> >  		return;
> >  
> >  	i3c_bus_for_each_i3cdev(&master->bus, desc) {
> > -		if (desc->dev || !desc->info.dyn_addr || desc == master->this)
> > +		if (desc->dev || !desc->info.dyn_addr ||
> > +		    desc == master->this || !desc->info.pid)
> >  			continue;
> >  
> >  		desc->dev = kzalloc(sizeof(*desc->dev), GFP_KERNEL);
> > @@ -1504,6 +1587,69 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
> >  	}
> >  }
> >  
> > +static struct i2c_dev_boardinfo *
> > +i3c_master_find_i2c_boardinfo(const struct i3c_master_controller *master,
> > +			      u16 addr, u8 lvr)
> 
> Same.
> 

Same :-)

> > +{
> > +	struct i2c_dev_boardinfo *i2cboardinfo;
> > +
> > +	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
> > +		if (i2cboardinfo->base.addr == addr &&
> > +		    i2cboardinfo->lvr == lvr)
> > +			return i2cboardinfo;
> > +	}
> > +
> > +	return NULL;
> > +}
> > +
> > +static void
> > +i3c_master_register_new_i2c_devs(struct i3c_master_controller *master)
> > +{
> > +	struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
> > +	struct i2c_dev_desc *i2cdev;
> > +
> > +	if (!master->init_done)
> > +		return;
> > +
> > +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> > +
> > +		if (i2cdev->dev)
> > +			continue;
> > +
> > +		if (!i2cdev->boardinfo)
> > +			continue;
> > +
> > +		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
> > +	}
> > +}
> > +
> > +static int i3c_master_get_accmst_locked(struct i3c_master_controller *master,
> > +					u8 addr)
> > +{
> > +	struct i3c_ccc_getaccmst *accmst;
> > +	struct i3c_ccc_cmd_dest dest;
> > +	struct i3c_ccc_cmd cmd;
> > +	int ret;
> > +
> > +	accmst = i3c_ccc_cmd_dest_init(&dest, addr, sizeof(*accmst));
> > +	if (!accmst)
> > +		return -ENOMEM;
> > +
> > +	i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETACCMST, &dest, 1);
> > +
> > +	ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
> > +	if (ret)
> > +		goto out;
> > +
> > +	if (dest.payload.len != sizeof(*accmst))
> > +		ret = -EIO;
> > +
> > +out:
> > +	i3c_ccc_cmd_dest_cleanup(&dest);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(i3c_master_get_accmst_locked);
> >  /**
> >   * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
> >   * @master: master doing the DAA
> > @@ -1548,10 +1694,6 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
> >  	if (!i3c_bus_dev_addr_is_avail(&master->bus, info->dyn_addr))
> >  		return -EINVAL;
> >  
> > -	if (I3C_BCR_DEVICE_ROLE(info->bcr) == I3C_BCR_I3C_MASTER &&
> > -	    master->secondary)
> > -		return -EINVAL;
> > -
> >  	if (master->this)
> >  		return -EINVAL;
> >  
> > @@ -1560,7 +1702,8 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
> >  		return PTR_ERR(i3cdev);
> >  
> >  	master->this = i3cdev;
> > -	master->bus.cur_master = master->this;
> > +	if (!secondary)
> > +		master->bus.cur_master = master->this;
> >  
> >  	ret = i3c_master_attach_i3c_dev(master, i3cdev);
> >  	if (ret)
> > @@ -1601,37 +1744,7 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
> >  	}
> >  }
> >  
> > -/**
> > - * i3c_master_bus_init() - initialize an I3C bus
> > - * @master: main master initializing the bus
> > - *
> > - * This function is following all initialisation steps described in the I3C
> > - * specification:
> > - *
> > - * 1. Attach I2C and statically defined I3C devs to the master so that the
> > - *    master can fill its internal device table appropriately
> > - *
> > - * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
> > - *    the master controller. That's usually where the bus mode is selected
> > - *    (pure bus or mixed fast/slow bus)
> > - *
> > - * 3. Instruct all devices on the bus to drop their dynamic address. This is
> > - *    particularly important when the bus was previously configured by someone
> > - *    else (for example the bootloader)
> > - *
> > - * 4. Disable all slave events.
> > - *
> > - * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
> > - *    devices that have a static address
> > - *
> > - * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
> > - *    remaining I3C devices
> > - *
> > - * Once this is done, all I3C and I2C devices should be usable.
> > - *
> > - * Return: a 0 in case of success, an negative error code otherwise.
> > - */
> > -static int i3c_master_bus_init(struct i3c_master_controller *master)
> > +static int i3c_master_attach_static_devs(struct i3c_master_controller *master)
> >  {
> >  	enum i3c_addr_slot_status status;
> >  	struct i2c_dev_boardinfo *i2cboardinfo;
> > @@ -1640,32 +1753,24 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
> >  	struct i2c_dev_desc *i2cdev;
> >  	int ret;
> >  
> > -	/*
> > -	 * First attach all devices with static definitions provided by the
> > -	 * FW.
> > -	 */
> >  	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
> >  		status = i3c_bus_get_addr_slot_status(&master->bus,
> >  						      i2cboardinfo->base.addr);
> > -		if (status != I3C_ADDR_SLOT_FREE) {
> > -			ret = -EBUSY;
> > -			goto err_detach_devs;
> > -		}
> > +		if (status != I3C_ADDR_SLOT_FREE)
> > +			return -EBUSY;
> >  
> >  		i3c_bus_set_addr_slot_status(&master->bus,
> >  					     i2cboardinfo->base.addr,
> >  					     I3C_ADDR_SLOT_I2C_DEV);
> >  
> >  		i2cdev = i3c_master_alloc_i2c_dev(master, i2cboardinfo);
> > -		if (IS_ERR(i2cdev)) {
> > -			ret = PTR_ERR(i2cdev);
> > -			goto err_detach_devs;
> > -		}
> > +		if (IS_ERR(i2cdev))
> > +			return PTR_ERR(i2cdev);
> >  
> >  		ret = i3c_master_attach_i2c_dev(master, i2cdev);
> >  		if (ret) {
> >  			i3c_master_free_i2c_dev(i2cdev);
> > -			goto err_detach_devs;
> > +			return ret;
> >  		}
> >  	}
> >  	list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) {
> > @@ -1676,27 +1781,68 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
> >  		if (i3cboardinfo->init_dyn_addr) {
> >  			status = i3c_bus_get_addr_slot_status(&master->bus,
> >  						i3cboardinfo->init_dyn_addr);
> > -			if (status != I3C_ADDR_SLOT_FREE) {
> > -				ret = -EBUSY;
> > -				goto err_detach_devs;
> > -			}
> > +			if (status != I3C_ADDR_SLOT_FREE)
> > +				return -EBUSY;
> >  		}
> >  
> >  		i3cdev = i3c_master_alloc_i3c_dev(master, &info);
> > -		if (IS_ERR(i3cdev)) {
> > -			ret = PTR_ERR(i3cdev);
> > -			goto err_detach_devs;
> > -		}
> > +		if (IS_ERR(i3cdev))
> > +			return PTR_ERR(i3cdev);
> >  
> >  		i3cdev->boardinfo = i3cboardinfo;
> >  
> >  		ret = i3c_master_attach_i3c_dev(master, i3cdev);
> >  		if (ret) {
> >  			i3c_master_free_i3c_dev(i3cdev);
> > -			goto err_detach_devs;
> > +			return ret;
> >  		}
> >  	}
> >  
> > +	return 0;
> > +}
> > +
> > +/**
> > + * i3c_master_bus_init() - initialize an I3C bus
> > + * @master: main master initializing the bus
> > + *
> > + * This function is following all initialisation steps described in the I3C
> > + * specification:
> > + *
> > + * 1. Attach I2C and statically defined I3C devs to the master so that the
> > + *    master can fill its internal device table appropriately
> > + *
> > + * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
> > + *    the master controller. That's usually where the bus mode is selected
> > + *    (pure bus or mixed fast/slow bus)
> > + *
> > + * 3. Instruct all devices on the bus to drop their dynamic address. This is
> > + *    particularly important when the bus was previously configured by someone
> > + *    else (for example the bootloader)
> > + *
> > + * 4. Disable all slave events.
> > + *
> > + * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
> > + *    devices that have a static address
> > + *
> > + * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
> > + *    remaining I3C devices
> > + *
> > + * Once this is done, all I3C and I2C devices should be usable.
> > + *
> > + * Return: a 0 in case of success, an negative error code otherwise.
> > + */
> > +static int i3c_master_bus_init(struct i3c_master_controller *master)
> > +{
> > +	struct i3c_dev_desc *i3cdev;
> > +	int ret;
> > +
> > +	/*
> > +	 * First attach all devices with static definitions provided by the
> > +	 * FW.
> > +	 */
> > +	ret = i3c_master_attach_static_devs(master);
> > +	if (ret)
> > +		goto err_detach_devs;
> >  	/*
> >  	 * Now execute the controller specific ->bus_init() routine, which
> >  	 * might configure its internal logic to match the bus limitations.
> > @@ -1780,45 +1926,76 @@ i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev)
> >  }
> >  
> >  /**
> > - * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> > - * @master: master used to send frames on the bus
> > - * @addr: I3C slave dynamic address assigned to the device
> > + * i3c_master_add_i2c_dev_locked() - add an I2C slave to the bus
> > + * @master: master used to register I2C device
> > + * @addr: I2C device address
> > + * @lvr: legacy virtual register value
> >   *
> > - * This function is instantiating an I3C device object and adding it to the
> > - * I3C device list. All device information are automatically retrieved using
> > - * standard CCC commands.
> > - *
> > - * The I3C device object is returned in case the master wants to attach
> > - * private data to it using i3c_dev_set_master_data().
> > + * This function is instantiating an I2C device object and adding it to the
> > + * I2C device list.
> >   *
> >   * This function must be called with the bus lock held in write mode.
> >   *
> >   * Return: a 0 in case of success, an negative error code otherwise.
> >   */
> > -int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > -				  u8 addr)
> > +int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
> > +				  u16 addr, u8 lvr)
> >  {
> > -	struct i3c_device_info info = { .dyn_addr = addr };
> > -	struct i3c_dev_desc *newdev, *olddev;
> > -	u8 old_dyn_addr = addr, expected_dyn_addr;
> > -	struct i3c_ibi_setup ibireq = { };
> > -	bool enable_ibi = false;
> > +	enum i3c_addr_slot_status status;
> > +	struct i2c_dev_desc *i2cdev;
> >  	int ret;
> >  
> >  	if (!master)
> >  		return -EINVAL;
> >  
> > -	newdev = i3c_master_alloc_i3c_dev(master, &info);
> > -	if (IS_ERR(newdev))
> > -		return PTR_ERR(newdev);
> > +	status = i3c_bus_get_addr_slot_status(&master->bus,
> > +					      addr);
> > +	if (status != I3C_ADDR_SLOT_FREE)
> > +		return -EBUSY;
> >  
> > -	ret = i3c_master_attach_i3c_dev(master, newdev);
> > -	if (ret)
> > +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> > +				     I3C_ADDR_SLOT_I2C_DEV);
> > +
> > +	i2cdev = i3c_master_alloc_i2c_dev_no_boardinfo(master, addr, lvr);
> > +
> > +	if (IS_ERR(i2cdev)) {
> > +		ret = PTR_ERR(i2cdev);
> > +		goto err_free_dev;
> > +	}
> > +
> > +	i2cdev->boardinfo = i3c_master_find_i2c_boardinfo(master, addr, lvr);
> > +
> > +	ret = i3c_master_attach_i2c_dev(master, i2cdev);
> > +
> > +	if (ret) {
> > +		ret = PTR_ERR(i2cdev);
> >  		goto err_free_dev;
> > +	}
> > +
> > +	return 0;
> > +
> > +err_free_dev:
> > +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> > +				     I3C_ADDR_SLOT_FREE);
> > +	i3c_master_free_i2c_dev(i2cdev);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(i3c_master_add_i2c_dev_locked);
> > +
> > +static int
> > +i3c_master_retrieve_info_and_reuse(struct i3c_master_controller *master,
> > +				   struct i3c_dev_desc *newdev)
> > +{
> > +	struct i3c_dev_desc *olddev;
> > +	u8 old_dyn_addr = newdev->info.dyn_addr, expected_dyn_addr;
> > +	struct i3c_ibi_setup ibireq = { };
> > +	bool enable_ibi = false;
> > +	int ret;
> >  
> >  	ret = i3c_master_retrieve_dev_info(newdev);
> >  	if (ret)
> > -		goto err_detach_dev;
> > +		return ret;
> >  
> >  	olddev = i3c_master_search_i3c_dev_duplicate(newdev);
> >  	if (olddev) {
> > @@ -1857,7 +2034,7 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> >  
> >  	ret = i3c_master_reattach_i3c_dev(newdev, old_dyn_addr);
> >  	if (ret)
> > -		goto err_detach_dev;
> > +		return ret;
> >  
> >  	/*
> >  	 * Depending on our previous state, the expected dynamic address might
> > @@ -1920,6 +2097,50 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> >  	}
> >  
> >  	return 0;
> > +}
> > +
> > +/**
> > + * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> > + * @master: master used to send frames on the bus
> > + * @addr: I3C slave dynamic address assigned to the device
> > + *
> > + * This function is instantiating an I3C device object and adding it to the
> > + * I3C device list. All device information are automatically retrieved using
> > + * standard CCC commands.
> > + *
> > + * The I3C device object is returned in case the master wants to attach
> > + * private data to it using i3c_dev_set_master_data().
> > + *
> > + * This function must be called with the bus lock held in write mode.
> > + *
> > + * Return: a 0 in case of success, an negative error code otherwise.
> > + */
> > +int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > +				  u8 addr)
> > +{
> > +	struct i3c_device_info info = { .dyn_addr = addr };
> > +	struct i3c_dev_desc *newdev;
> > +	int ret;
> > +
> > +	if (!master)
> > +		return -EINVAL;
> > +
> > +	newdev = i3c_master_alloc_i3c_dev(master, &info);
> > +	if (IS_ERR(newdev))
> > +		return PTR_ERR(newdev);
> > +
> > +	ret = i3c_master_attach_i3c_dev(master, newdev);
> > +	if (ret)
> > +		goto err_free_dev;
> > +
> > +	if (i3c_master_owns_bus(master)) {
> > +		ret = i3c_master_retrieve_info_and_reuse(master, newdev);
> > +		if (ret)
> > +			goto err_detach_dev;
> > +	} else
> > +		master->want_to_acquire_bus = true;
> > +
> > +	return 0;
> >  
> >  err_detach_dev:
> >  	if (newdev->dev && newdev->dev->desc)
> > @@ -2101,11 +2322,15 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
> >  	}
> >  
> >  	i3c_bus_normaluse_lock(&master->bus);
> > +	ret = i3c_master_acquire_bus_ownership(master);
> > +	if (ret)
> > +		goto err_unlock_bus;
> >  	dev = i3c_master_find_i2c_dev_by_addr(master, addr);
> >  	if (!dev)
> >  		ret = -ENOENT;
> >  	else
> >  		ret = master->ops->i2c_xfers(dev, xfers, nxfers);
> > +err_unlock_bus:
> >  	i3c_bus_normaluse_unlock(&master->bus);
> >  
> >  	return ret ? ret : nxfers;
> > @@ -2144,9 +2369,12 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
> >  	 * We silently ignore failures here. The bus should keep working
> >  	 * correctly even if one or more i2c devices are not registered.
> >  	 */
> > -	i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
> > +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> > +		if (!i2cdev->boardinfo)
> > +			continue;
> >  		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
> >  
> > +	}
> >  	return 0;
> >  }
> >  
> > @@ -2385,9 +2613,76 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
> >  	     !ops->recycle_ibi_slot))
> >  		return -EINVAL;
> >  
> > +	/*
> > +	 * If mastership request is supported, we also need hooks to control
> > +	 * when mastership request can occur by enabling/disabling the event.
> > +	 */
> > +	if (ops->request_mastership &&
> > +	    (!ops->enable_mr_events || !ops->disable_mr_events))
> > +		return -EINVAL;
> >  	return 0;
> >  }
> >  
> > +static void i3c_master_register_new_devs(struct i3c_master_controller *master)
> > +{
> > +	/*
> > +	 * We can register devices received from master by DEFSLVS.
> > +	 */
> > +	i3c_bus_normaluse_lock(&master->bus);
> > +	i3c_master_register_new_i3c_devs(master);
> > +	i3c_master_register_new_i2c_devs(master);
> > +	i3c_bus_normaluse_unlock(&master->bus);
> > +}
> > +
> > +/**
> > + * i3c_master_bus_takeover() - register new I3C devices on bus takeover
> > + * @master: master used to send frames on the bus
> > + *
> > + * This function is useful when devices were not added
> > + * during initialization or when new device joined the bus
> > + * which wasn't under our control.
> > + */
> > +void i3c_master_bus_takeover(struct i3c_master_controller *master)
> > +{
> > +	struct i3c_dev_desc *i3cdev, *i3ctmp;
> > +	int ret;
> > +
> > +	master->want_to_acquire_bus = false;
> 
> Can you explain the usage of this variable?
> 

The idea of this was to let HC know that we want to acquire the bus after
ENEC(MR) received in slave mode.

> > +
> > +	if (!master->init_done)
> > +		return;
> > +
> > +	i3c_bus_maintenance_lock(&master->bus);
> > +	master->ops->populate_bus(master);
> > +
> > +	list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c,
> > +				 common.node) {
> > +		if (i3cdev->info.pid)
> > +			continue;
> > +
> > +		ret = i3c_master_retrieve_info_and_reuse(master, i3cdev);
> > +		if (ret) {
> > +			if (i3cdev->dev && i3cdev->dev->desc)
> > +				i3cdev->dev->desc = NULL;
> > +
> > +			i3c_master_detach_i3c_dev(i3cdev);
> > +		}
> > +	}
> > +
> > +	/*
> > +	 * If current master finished bus initialization properly, we can
> > +	 * enable Mastership event.
> > +	 */
> > +	ret = i3c_master_enable_mr_events_locked(master);
> > +	if (ret)
> > +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> > +
> > +	i3c_bus_maintenance_unlock(&master->bus);
> > +
> > +	i3c_master_register_new_devs(master);
> > +}
> > +EXPORT_SYMBOL_GPL(i3c_master_bus_takeover);
> > +
> >  /**
> >   * i3c_master_init() - initializes all the structures required by I3C master
> >   * @master: master used to send frames on the bus
> > @@ -2417,9 +2712,6 @@ int i3c_master_init(struct i3c_master_controller *master,
> >  	struct i2c_dev_boardinfo *i2cbi;
> >  	int ret;
> >  
> > -	/* We do not support secondary masters yet. */
> > -	if (secondary)
> > -		return -ENOTSUPP;
> >  
> >  	ret = i3c_master_check_ops(ops);
> >  	if (ret)
> > @@ -2432,6 +2724,7 @@ int i3c_master_init(struct i3c_master_controller *master,
> >  	master->dev.release = i3c_masterdev_release;
> >  	master->ops = ops;
> >  	master->secondary = secondary;
> > +	master->want_to_acquire_bus = secondary;
> >  	INIT_LIST_HEAD(&master->boardinfo.i2c);
> >  	INIT_LIST_HEAD(&master->boardinfo.i3c);
> >  
> > @@ -2488,6 +2781,92 @@ void i3c_master_cleanup(struct i3c_master_controller *master)
> >  EXPORT_SYMBOL_GPL(i3c_master_cleanup);
> >  
> >  /**
> > + * i3c_secondary_master_register() - register an secondary I3C master
> > + * @master: master used to send frames on the bus
> > + * @info: master info, describes this device
> > + *
> > + * This function takes care of everything for you:
> > + *
> > + * - updates this master info
> > + * - registers the I2C adapter
> > + * - if possible, populates the bus with devices received by DEFSLVS
> > + *   command
> > + *
> > + * Return: 0 in case of success, a negative error code otherwise.
> > + */
> > +int i3c_secondary_master_register(struct i3c_master_controller *master,
> > +				  struct i3c_device_info *info)
> > +{
> > +	int ret;
> > +
> > +	ret = i3c_master_set_info(master, info, master->secondary);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = master->ops->bus_init(master);
> > +	if (ret)
> > +		return ret;
> 
> At this point you don't have enough information to do the bus 
> initialization.
> 

Actually, current ->bus_init() implementations (in CDNS and DW) does not
initialize the bus. We are just setting the mode, configuring some init values
in the registers and enabling the core. Maybe we should rename it?

> > +
> > +	ret = device_add(&master->dev);
> > +	if (ret)
> > +		return -1;
> > +
> > +	/*
> > +	 * Expose our I3C bus as an I2C adapter so that I2C devices are exposed
> > +	 * through the I2C subsystem.
> > +	 */
> > +	ret = i3c_master_i2c_adapter_init(master);
> > +	if (ret)
> > +		goto err_del_dev;
> > +
> > +	i3c_bus_maintenance_lock(&master->bus);
> > +	/*
> > +	 * If possible, request mastership and try to populate the bus.
> > +	 */
> > +	ret = i3c_master_request_mastership_locked(master);
> > +	if (ret)
> > +		dev_warn(&master->dev,
> > +			 "Mastership failed at init time (ret = %i)", ret);
> > +
> > +	/*
> > +	 * No matter if mastership takeover passed or not, add partialy
> > +	 * discovered devices. We can register them when ENEC(MR) is enabled.
> > +	 */
> > +	master->ops->populate_bus(master);
> > +
> > +	i3c_bus_maintenance_unlock(&master->bus);
> > +
> > +	/*
> > +	 * We're done initializing the bus and the controller, we can now
> > +	 * register I3C devices obtained by DEFSLVS.
> > +	 */
> > +	master->init_done = true;
> > +	i3c_master_register_new_devs(master);
> > +
> > +	/*
> > +	 * If we are owning the bus, enable ENEC(MR) to let other masters
> > +	 * initialize their bus.
> > +	 */
> > +	if (i3c_master_owns_bus(master)) {
> > +		i3c_bus_maintenance_lock(&master->bus);
> > +		ret = i3c_master_enable_mr_events_locked(master);
> > +		i3c_bus_maintenance_unlock(&master->bus);
> > +		if (ret)
> > +			dev_warn(&master->dev,
> > +				 "ENEC(MR) failed (ret = %i)", ret);
> > +	}
> > +
> > +
> > +	return 0;
> > +
> > +err_del_dev:
> > +	device_del(&master->dev);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(i3c_secondary_master_register);
> > +
> > +/**
> >   * i3c_master_register() - register an primary I3C master
> >   * @master: master used to send frames on the bus
> >   * @info: master info, describes this device
> > @@ -2509,7 +2888,6 @@ int i3c_master_register(struct i3c_master_controller *master,
> >  	ret = i3c_master_set_info(master, info, master->secondary);
> >  	if (ret)
> >  		return ret;
> > -
> >  	ret = i3c_master_bus_init(master);
> >  	if (ret)
> >  		return ret;
> > @@ -2535,6 +2913,16 @@ int i3c_master_register(struct i3c_master_controller *master,
> >  	i3c_master_register_new_i3c_devs(master);
> >  	i3c_bus_normaluse_unlock(&master->bus);
> >  
> > +	/*
> > +	 * Enable ENEC(MR) and let other masters request mastership
> > +	 * and initialize their bus.
> > +	 */
> > +	i3c_bus_maintenance_lock(&master->bus);
> > +	ret = i3c_master_enable_mr_events_locked(master);
> > +	i3c_bus_maintenance_unlock(&master->bus);
> > +	if (ret)
> > +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> > +
> >  	return 0;
> >  
> >  err_del_dev:
> > @@ -2548,6 +2936,29 @@ int i3c_master_register(struct i3c_master_controller *master,
> >  EXPORT_SYMBOL_GPL(i3c_master_register);
> >  
> >  /**
> > + * i3c_master_mastership_ack() - acknowledges bus takeover.
> > + * @master: master used to send frames on the bus
> > + * @addr: I3C device address
> > + *
> > + * This function acknowledges bus takeover.
> > + *
> > + * Return: 0 in case of success, a negative error code otherwise.
> > + */
> > +int i3c_master_mastership_ack(struct i3c_master_controller *master,
> > +			      u8 addr)
> > +{
> > +	int ret;
> > +
> > +	i3c_bus_maintenance_lock(&master->bus);
> > +	ret = i3c_master_get_accmst_locked(master, addr);
> > +	i3c_bus_maintenance_unlock(&master->bus);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(i3c_master_mastership_ack);
> > +
> > +
> > +/**
> >   * i3c_master_unregister() - unregister an I3C master
> >   * @master: master used to send frames on the bus
> >   *
> > @@ -2557,6 +2968,9 @@ EXPORT_SYMBOL_GPL(i3c_master_register);
> >   */
> >  int i3c_master_unregister(struct i3c_master_controller *master)
> >  {
> > +	i3c_bus_maintenance_lock(&master->bus);
> > +	i3c_master_disable_mr_events(master);
> > +	i3c_bus_maintenance_unlock(&master->bus);
> >  	i3c_master_i2c_adapter_cleanup(master);
> >  	i3c_master_unregister_i3c_devs(master);
> >  	i3c_master_bus_cleanup(master);
> > diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
> > index e089771..6ac9b46 100644
> > --- a/include/linux/i3c/master.h
> > +++ b/include/linux/i3c/master.h
> > @@ -421,6 +421,26 @@ struct i3c_bus {
> >   *		      for a future IBI
> >   *		      This method is mandatory only if ->request_ibi is not
> >   *		      NULL.
> > + * @request_mastership: requests bus mastership. Mastership is requested
> > + *                      automatically when device driver wants to transfer
> > + *                      data using a master that does not currently
> > + *                      owns the bus.
> > + * @enable_mr_events: enable the Mastership event. Master driver can prepare
> > + *                    its internal state to be ready for incoming mastership
> > + *                    requests and then should send ENEC(MR) command to let
> > + *                    other masters take control over the bus.
> > + * @disable_mr_events: disable the Mastership event. Master driver should
> > + *                     immediately send DISEC(MR) command and can perform other
> > + *                     operations. For example, recycle IBI slot if used before
> > + *                     for MR event.
> > + * @populate_pus: populates the bus. Called after bus takeover. Secondary
> > + *                master can't perform DAA procedure. This function allows to
> > + *                update devices received from previous bus owner in DEFSLVS
> > + *                command. Useful also when new device joins the bus controlled
> > + *                by secondary master, main master will be able to add
> > + *                this device after mastership takeover. Driver should also
> > + *		  update bus mode when I2C device is on the bus.
> > + *
> >   */
> >  struct i3c_master_controller_ops {
> >  	int (*bus_init)(struct i3c_master_controller *master);
> > @@ -447,6 +467,10 @@ struct i3c_master_controller_ops {
> >  	int (*disable_ibi)(struct i3c_dev_desc *dev);
> >  	void (*recycle_ibi_slot)(struct i3c_dev_desc *dev,
> >  				 struct i3c_ibi_slot *slot);
> > +	int (*request_mastership)(struct i3c_master_controller *master);
> > +	int (*enable_mr_events)(struct i3c_master_controller *master);
> > +	int (*disable_mr_events)(struct i3c_master_controller *master);
> > +	int (*populate_bus)(struct i3c_master_controller *master);
> >  };
> >  
> >  /**
> > @@ -488,6 +512,7 @@ struct i3c_master_controller {
> >  	} boardinfo;
> >  	struct i3c_bus bus;
> >  	struct workqueue_struct *wq;
> > +	bool want_to_acquire_bus;
> >  };
> >  
> >  /**
> > @@ -526,6 +551,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master);
> >  int i3c_master_get_free_addr(struct i3c_master_controller *master,
> >  			     u8 start_addr);
> >  
> > +int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
> > +				  u16 addr, u8 lvr);
> >  int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> >  				  u8 addr);
> >  int i3c_master_do_daa(struct i3c_master_controller *master);
> > @@ -535,9 +562,14 @@ int i3c_master_init(struct i3c_master_controller *master,
> >  		    const struct i3c_master_controller_ops *ops,
> >  		    bool secondary);
> >  void i3c_master_cleanup(struct i3c_master_controller *master);
> > +int i3c_secondary_master_register(struct i3c_master_controller *master,
> > +				  struct i3c_device_info *info);
> >  int i3c_master_register(struct i3c_master_controller *master,
> >  			struct i3c_device_info *info);
> >  int i3c_master_unregister(struct i3c_master_controller *master);
> > +int i3c_master_mastership_ack(struct i3c_master_controller *master,
> > +			      u8 addr);
> > +void i3c_master_bus_takeover(struct i3c_master_controller *master);
> >  int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode);
> >  
> >  /**
> > @@ -648,7 +680,5 @@ void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot);
> >  
> >  struct i3c_ibi_slot *i3c_master_get_free_ibi_slot(struct i3c_dev_desc *dev);
> >  
> > -void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> > -void i3c_bus_maintenance_unlock(struct i3c_bus *bus);
> >  
> >  #endif /* I3C_MASTER_H */
> > -- 
> > 2.4.5
> 
> In generally I found this intrusive for the current eco system.
> 
> I propose the following:
> 1 - Keep the function i3c_master_register() as is and go out before 

We had that version previously. We decided to split it.

> i3c_master_bus_init() if secondary master.
> @Boris Brezillon is it possible to replace device_initialize() device_add() with device_register()?
> 
> 2 - When received DEFSLVS commands add devices to a link list like 
> boardinfo.

If DEFSLVS received devices are partialy added at init time.

>   Get bus ownership if there is DEFSLVS to add or secondary master not 
> initialized. 
> 
> 3 - When received ENEC MR

I thought it works like that :-) When ENEC(MR) received, HC driver adds devices
from DEFSLVS frame,

>   Get bus ownership if there is DEFSLVS to add or secondary master not 
> initialized.
> 
> 4 - When secondary master became current master.

and calls i3c_master_bus_takeover() to let subsystem gather device information
and register them.

>   Attach new devices to the host controller and retrieve device info 
> (same logic as in i3c_master_add_i3c_dev_locked).
> 
> With this approach on HC side you just need to add the secondary master 
> stuff without changing the current code and leave for the subsystem the 
> responsible to manage all these secondary master task.

This may be difficult for some controllers, depends where DEFSLVS device
information is stored. I also cannot find information about that part in
MIPI I3C HCI specification. This part can be vendor specific. What do you
think?

> 
> Let me know if this works for you.
> 
> 
> Best regards,
> Vitor Soares

-- 
-- 
Przemyslaw Gaj

_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem
  2019-07-11  5:28     ` Przemyslaw Gaj
@ 2019-07-11 10:11       ` Vitor Soares
  2019-07-12 10:10         ` Przemyslaw Gaj
  0 siblings, 1 reply; 21+ messages in thread
From: Vitor Soares @ 2019-07-11 10:11 UTC (permalink / raw)
  To: Przemyslaw Gaj, Vitor Soares; +Cc: linux-i3c, agolec, rafalc, bbrezillon

From: Przemyslaw Gaj <pgaj@cadence.com>
Date: Thu, Jul 11, 2019 at 06:28:18

> Hi Vitor,
> 
> The 07/10/2019 18:04, Vitor Soares wrote:
> > EXTERNAL MAIL
> > 
> > 
> > From: Przemyslaw Gaj <pgaj@cadence.com>
> > Date: Sat, Jun 22, 2019 at 21:55:02
> > 
> > > This patch adds support for mastership request to I3C subsystem.
> > > 
> > > Mastership event is enabled globally.
> > > 
> > > Mastership is requested automatically when device driver
> > > tries to transfer data using master controller in slave mode.
> > > 
> > > There is still some limitation:
> > > - I2C devices are registered on secondary master side if boardinfo
> > > entry matching the info transmitted through the DEFSLVS frame.
> > > 
> > > Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
> > > 
> > > ---
> > > 
> > > Main changes between v4 and v5:
> > > - Add function to test if master owns the bus
> > > - Add i3c_secondary_master_register() function
> > > - Add populate_bus() hook to populate the bus after mastership takeover
> > 
> > For me this task is for the sub-system not the host controller.
> > 
> 
> I'm not sure where device information is stored in DW controller but in CDNS
> controller DEFSLVS frame is processed in the device and the only thing I got is
> information that DEFSLVS came in. 

When you receive this notification you can add the device to subsystem to 
be initialized later when get bus ownership.

> I need to inform subsystem that there are new
> device (if any).
> I remember we talkad about that already, you have access to
> DEFSLVS information directly, correct?

I can process it in the HC driver, but my point is that I want to rely it 
to the subsystem the bus population with the function already present.

> 
> > > - Rework device information retrieval to allow adding partialy discovered
> > > devices
> > > 
> > > Main changes between v3 and v4:
> > > - Add i3c_master_acquire_bus_ownership to acquire the bus
> > > - Refactored the code
> > > 
> > > Main changes between v2 and v3:
> > > - Add i3c_bus_downgrade_maintenance_lock() for downgrading the bus
> > > lock from maintenance to normal use
> > > - Add additional fields to i2c_dev_desc for DEFSLVS purpose (addr, lvr)
> > > - Add i3c_master_register_new_i2c_devs() function to register I2C devices
> > > - Reworked I2C devices registration on secondary master side
> > > 
> > > Changes in v2:
> > > - Add mastership disable event hook
> > > - Changed name of mastership enable event hook
> > > - Add function to test if master owns the bus
> > > - Removed op_mode
> > > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > > pass full i3c_device_info
> > > - Changed name of mastership enable event hook
> > > - Add function to test if master owns the bus
> > > - Removed op_mode
> > > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > > pass full i3c_device_info
> > > - Removed redundant DEFSLVS command before GETACCMST
> > > - Add i3c_master_bus_takeover function. There is a need to lock
> > > the bus before adding devices and no matter of the controller
> > > devices have to be added after mastership takeover.
> > > - Add device registration during initialization on secondary master
> > > side. Devices received by DEFSLVS (if occured). If not, device
> > > initialization is deffered untill next mastership request.
> > > ---
> > >  drivers/i3c/device.c       |  26 ++
> > >  drivers/i3c/internals.h    |   4 +
> > >  drivers/i3c/master.c       | 588 ++++++++++++++++++++++++++++++++++++++-------
> > >  include/linux/i3c/master.h |  34 ++-
> > >  4 files changed, 563 insertions(+), 89 deletions(-)
> > > 
> > > diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
> > > index 69cc040..b60f637 100644
> > > --- a/drivers/i3c/device.c
> > > +++ b/drivers/i3c/device.c
> > > @@ -43,7 +43,13 @@ int i3c_device_do_priv_xfers(struct i3c_device *dev,
> > >  	}
> > >  
> > >  	i3c_bus_normaluse_lock(dev->bus);
> > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > +	if (ret)
> > > +		goto err_unlock_bus;
> > > +
> > >  	ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
> > > +
> > > +err_unlock_bus:
> > >  	i3c_bus_normaluse_unlock(dev->bus);
> > >  
> > >  	return ret;
> > > @@ -114,11 +120,17 @@ int i3c_device_enable_ibi(struct i3c_device *dev)
> > >  	int ret = -ENOENT;
> > >  
> > >  	i3c_bus_normaluse_lock(dev->bus);
> > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > +	if (ret)
> > > +		goto err_unlock_bus;
> > > +
> > >  	if (dev->desc) {
> > >  		mutex_lock(&dev->desc->ibi_lock);
> > >  		ret = i3c_dev_enable_ibi_locked(dev->desc);
> > >  		mutex_unlock(&dev->desc->ibi_lock);
> > >  	}
> > > +
> > > +err_unlock_bus:
> > >  	i3c_bus_normaluse_unlock(dev->bus);
> > >  
> > >  	return ret;
> > > @@ -145,11 +157,17 @@ int i3c_device_request_ibi(struct i3c_device *dev,
> > >  		return -EINVAL;
> > >  
> > >  	i3c_bus_normaluse_lock(dev->bus);
> > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > +	if (ret)
> > > +		goto err_unlock_bus;
> > > +
> > >  	if (dev->desc) {
> > >  		mutex_lock(&dev->desc->ibi_lock);
> > >  		ret = i3c_dev_request_ibi_locked(dev->desc, req);
> > >  		mutex_unlock(&dev->desc->ibi_lock);
> > >  	}
> > > +
> > > +err_unlock_bus:
> > >  	i3c_bus_normaluse_unlock(dev->bus);
> > >  
> > >  	return ret;
> > > @@ -166,12 +184,20 @@ EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
> > >   */
> > >  void i3c_device_free_ibi(struct i3c_device *dev)
> > >  {
> > > +	int ret;
> > > +
> > >  	i3c_bus_normaluse_lock(dev->bus);
> > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > +	if (ret)
> > > +		goto err_unlock_bus;
> > > +
> > >  	if (dev->desc) {
> > >  		mutex_lock(&dev->desc->ibi_lock);
> > >  		i3c_dev_free_ibi_locked(dev->desc);
> > >  		mutex_unlock(&dev->desc->ibi_lock);
> > >  	}
> > > +
> > > +err_unlock_bus:
> > >  	i3c_bus_normaluse_unlock(dev->bus);
> > >  }
> > >  EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
> > > diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
> > > index 86b7b44..cdfc5bf 100644
> > > --- a/drivers/i3c/internals.h
> > > +++ b/drivers/i3c/internals.h
> > > @@ -14,6 +14,10 @@ extern struct bus_type i3c_bus_type;
> > >  
> > >  void i3c_bus_normaluse_lock(struct i3c_bus *bus);
> > >  void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
> > > +void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> > > +void i3c_bus_maintenance_unlock(struct i3c_bus *bus);
> > 
> > These function are static.
> > 
> 
> I forgot to revert that change to previous state.
> 
> > > +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master);
> > > +
> > 
> > What do you think to pass this logic to master.c?
> > 
> 
> Isn't it there?

I meant make it static and remove its call from device.c.

> 
> > >  
> > >  int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
> > >  				 struct i3c_priv_xfer *xfers,
> > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> > > index cbace14..3b44e66 100644
> > > --- a/drivers/i3c/master.c
> > > +++ b/drivers/i3c/master.c
> > > @@ -93,6 +93,18 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
> > >  	up_read(&bus->lock);
> > >  }
> > >  
> > > +/*
> > > + * i3c_bus_downgrade_maintenance_lock - Downgrade the bus lock to normal
> > > + * operation
> > > + *
> > > + * Should be called when a maintenance operation is done and normal
> > > + * operation is planned. See i3c_bus_maintenance_lock() and
> > > + * i3c_bus_normaluse_lock() for more details.
> > > + */
> > > +static void i3c_bus_downgrade_maintenance_lock(struct i3c_bus *bus)
> > > +{
> > > +	downgrade_write(&bus->lock);
> > > +}
> > >  static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
> > >  {
> > >  	return container_of(dev, struct i3c_master_controller, dev);
> > > @@ -341,6 +353,22 @@ static int i3c_device_probe(struct device *dev)
> > >  	return driver->probe(i3cdev);
> > >  }
> > >  
> > > +static int
> > > +i3c_master_enable_mr_events_locked(struct i3c_master_controller *master)
> > > +{
> > > +	if (!master->ops->enable_mr_events)
> > > +		return -ENOTSUPP;
> > > +
> > > +	return master->ops->enable_mr_events(master);
> > > +}
> > > +
> > > +static void i3c_master_disable_mr_events(struct i3c_master_controller *master)
> > > +{
> > > +	if (!master->ops->disable_mr_events)
> > > +		return;
> > > +
> > > +	master->ops->disable_mr_events(master);
> > > +}
> > 
> > Add new line.
> > 
> > It is not clear to me what you expect with these functions. Do you want 
> > to enable MR from all devices? Just some of them? How do you decide which 
> > secondary masters are allow earn the bus ownership?
> > 
> 
> We discussed this also. For now, we enable ENEC for all masters on the bus, we
> can change it later if needed. 

I would say to expand the current ibi framework to accommodate MR and 
also add platform entry to allow secondary masters on the bus.

> Also, priority level is encoded in slave address
> so current master will give the control to the master with lower address first.
> It shouldn't be a problem.

You can have security issues and the devices on the bus might not be 
prepared to work in multi-master environment.

> 
> > >  static int i3c_device_remove(struct device *dev)
> > >  {
> > >  	struct i3c_device *i3cdev = dev_to_i3cdev(dev);
> > > @@ -462,6 +490,42 @@ static int i3c_bus_init(struct i3c_bus *i3cbus)
> > >  	return 0;
> > >  }
> > >  
> > > +static int
> > > +i3c_master_request_mastership_locked(struct i3c_master_controller *master)
> > > +{
> > > +	if (WARN_ON(master->init_done &&
> > > +	    !rwsem_is_locked(&master->bus.lock)))
> > > +		return -EINVAL;
> > > +
> > > +	if (!master->ops->request_mastership)
> > > +		return -ENOTSUPP;
> > > +
> > > +	return master->ops->request_mastership(master);
> > > +}
> > > +
> > > +static int i3c_master_owns_bus(struct i3c_master_controller *master)
> > > +{
> > > +	return (master->bus.cur_master == master->this);
> > > +}
> > > +
> > > +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master)
> > > +{
> > > +	int ret;
> > > +
> > > +	if (!i3c_master_owns_bus(master)) {
> > > +		i3c_bus_normaluse_unlock(&master->bus);
> > > +		i3c_bus_maintenance_lock(&master->bus);
> > > +
> > > +		ret = i3c_master_request_mastership_locked(master);
> > > +		if (ret) {
> > > +			i3c_bus_maintenance_unlock(&master->bus);
> > > +			return ret;
> > > +		}
> > > +		i3c_bus_downgrade_maintenance_lock(&master->bus);
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > >  static const char * const i3c_bus_mode_strings[] = {
> > >  	[I3C_BUS_MODE_PURE] = "pure",
> > >  	[I3C_BUS_MODE_MIXED_FAST] = "mixed-fast",
> > > @@ -636,6 +700,22 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
> > >  	return dev;
> > >  }
> > >  
> > > +static struct i2c_dev_desc *
> > > +i3c_master_alloc_i2c_dev_no_boardinfo(struct i3c_master_controller *master,
> > > +				      u16 addr, u8 lvr)
> > 
> > u8 addr.
> > 
> 
> Originaly I2C address is u16 but we can change it as we know DEFSLVS does not
> support 10bit addresses.
> 
> > > +{
> > > +	struct i2c_dev_desc *dev;
> > > +
> > > +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> > > +	if (!dev)
> > > +		return ERR_PTR(-ENOMEM);
> > > +
> > > +	dev->common.master = master;
> > > +	dev->addr = addr;
> > > +	dev->lvr = lvr;
> > > +
> > > +	return dev;
> > > +}
> > >  static void *i3c_ccc_cmd_dest_init(struct i3c_ccc_cmd_dest *dest, u8 addr,
> > >  				   u16 payloadlen)
> > >  {
> > > @@ -705,6 +785,8 @@ i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master,
> > >  	struct i2c_dev_desc *dev;
> > >  
> > >  	i3c_bus_for_each_i2cdev(&master->bus, dev) {
> > > +		if (!dev->boardinfo)
> > > +			continue;
> > >  		if (dev->boardinfo->base.addr == addr)
> > >  			return dev;
> > >  	}
> > > @@ -1478,7 +1560,8 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
> > >  		return;
> > >  
> > >  	i3c_bus_for_each_i3cdev(&master->bus, desc) {
> > > -		if (desc->dev || !desc->info.dyn_addr || desc == master->this)
> > > +		if (desc->dev || !desc->info.dyn_addr ||
> > > +		    desc == master->this || !desc->info.pid)
> > >  			continue;
> > >  
> > >  		desc->dev = kzalloc(sizeof(*desc->dev), GFP_KERNEL);
> > > @@ -1504,6 +1587,69 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
> > >  	}
> > >  }
> > >  
> > > +static struct i2c_dev_boardinfo *
> > > +i3c_master_find_i2c_boardinfo(const struct i3c_master_controller *master,
> > > +			      u16 addr, u8 lvr)
> > 
> > Same.
> > 
> 
> Same :-)
> 
> > > +{
> > > +	struct i2c_dev_boardinfo *i2cboardinfo;
> > > +
> > > +	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
> > > +		if (i2cboardinfo->base.addr == addr &&
> > > +		    i2cboardinfo->lvr == lvr)
> > > +			return i2cboardinfo;
> > > +	}
> > > +
> > > +	return NULL;
> > > +}
> > > +
> > > +static void
> > > +i3c_master_register_new_i2c_devs(struct i3c_master_controller *master)
> > > +{
> > > +	struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
> > > +	struct i2c_dev_desc *i2cdev;
> > > +
> > > +	if (!master->init_done)
> > > +		return;
> > > +
> > > +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> > > +
> > > +		if (i2cdev->dev)
> > > +			continue;
> > > +
> > > +		if (!i2cdev->boardinfo)
> > > +			continue;
> > > +
> > > +		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
> > > +	}
> > > +}
> > > +
> > > +static int i3c_master_get_accmst_locked(struct i3c_master_controller *master,
> > > +					u8 addr)
> > > +{
> > > +	struct i3c_ccc_getaccmst *accmst;
> > > +	struct i3c_ccc_cmd_dest dest;
> > > +	struct i3c_ccc_cmd cmd;
> > > +	int ret;
> > > +
> > > +	accmst = i3c_ccc_cmd_dest_init(&dest, addr, sizeof(*accmst));
> > > +	if (!accmst)
> > > +		return -ENOMEM;
> > > +
> > > +	i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETACCMST, &dest, 1);
> > > +
> > > +	ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
> > > +	if (ret)
> > > +		goto out;
> > > +
> > > +	if (dest.payload.len != sizeof(*accmst))
> > > +		ret = -EIO;
> > > +
> > > +out:
> > > +	i3c_ccc_cmd_dest_cleanup(&dest);
> > > +
> > > +	return ret;
> > > +}
> > > +EXPORT_SYMBOL_GPL(i3c_master_get_accmst_locked);
> > >  /**
> > >   * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
> > >   * @master: master doing the DAA
> > > @@ -1548,10 +1694,6 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
> > >  	if (!i3c_bus_dev_addr_is_avail(&master->bus, info->dyn_addr))
> > >  		return -EINVAL;
> > >  
> > > -	if (I3C_BCR_DEVICE_ROLE(info->bcr) == I3C_BCR_I3C_MASTER &&
> > > -	    master->secondary)
> > > -		return -EINVAL;
> > > -
> > >  	if (master->this)
> > >  		return -EINVAL;
> > >  
> > > @@ -1560,7 +1702,8 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
> > >  		return PTR_ERR(i3cdev);
> > >  
> > >  	master->this = i3cdev;
> > > -	master->bus.cur_master = master->this;
> > > +	if (!secondary)
> > > +		master->bus.cur_master = master->this;
> > >  
> > >  	ret = i3c_master_attach_i3c_dev(master, i3cdev);
> > >  	if (ret)
> > > @@ -1601,37 +1744,7 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
> > >  	}
> > >  }
> > >  
> > > -/**
> > > - * i3c_master_bus_init() - initialize an I3C bus
> > > - * @master: main master initializing the bus
> > > - *
> > > - * This function is following all initialisation steps described in the I3C
> > > - * specification:
> > > - *
> > > - * 1. Attach I2C and statically defined I3C devs to the master so that the
> > > - *    master can fill its internal device table appropriately
> > > - *
> > > - * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
> > > - *    the master controller. That's usually where the bus mode is selected
> > > - *    (pure bus or mixed fast/slow bus)
> > > - *
> > > - * 3. Instruct all devices on the bus to drop their dynamic address. This is
> > > - *    particularly important when the bus was previously configured by someone
> > > - *    else (for example the bootloader)
> > > - *
> > > - * 4. Disable all slave events.
> > > - *
> > > - * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
> > > - *    devices that have a static address
> > > - *
> > > - * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
> > > - *    remaining I3C devices
> > > - *
> > > - * Once this is done, all I3C and I2C devices should be usable.
> > > - *
> > > - * Return: a 0 in case of success, an negative error code otherwise.
> > > - */
> > > -static int i3c_master_bus_init(struct i3c_master_controller *master)
> > > +static int i3c_master_attach_static_devs(struct i3c_master_controller *master)
> > >  {
> > >  	enum i3c_addr_slot_status status;
> > >  	struct i2c_dev_boardinfo *i2cboardinfo;
> > > @@ -1640,32 +1753,24 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
> > >  	struct i2c_dev_desc *i2cdev;
> > >  	int ret;
> > >  
> > > -	/*
> > > -	 * First attach all devices with static definitions provided by the
> > > -	 * FW.
> > > -	 */
> > >  	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
> > >  		status = i3c_bus_get_addr_slot_status(&master->bus,
> > >  						      i2cboardinfo->base.addr);
> > > -		if (status != I3C_ADDR_SLOT_FREE) {
> > > -			ret = -EBUSY;
> > > -			goto err_detach_devs;
> > > -		}
> > > +		if (status != I3C_ADDR_SLOT_FREE)
> > > +			return -EBUSY;
> > >  
> > >  		i3c_bus_set_addr_slot_status(&master->bus,
> > >  					     i2cboardinfo->base.addr,
> > >  					     I3C_ADDR_SLOT_I2C_DEV);
> > >  
> > >  		i2cdev = i3c_master_alloc_i2c_dev(master, i2cboardinfo);
> > > -		if (IS_ERR(i2cdev)) {
> > > -			ret = PTR_ERR(i2cdev);
> > > -			goto err_detach_devs;
> > > -		}
> > > +		if (IS_ERR(i2cdev))
> > > +			return PTR_ERR(i2cdev);
> > >  
> > >  		ret = i3c_master_attach_i2c_dev(master, i2cdev);
> > >  		if (ret) {
> > >  			i3c_master_free_i2c_dev(i2cdev);
> > > -			goto err_detach_devs;
> > > +			return ret;
> > >  		}
> > >  	}
> > >  	list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) {
> > > @@ -1676,27 +1781,68 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
> > >  		if (i3cboardinfo->init_dyn_addr) {
> > >  			status = i3c_bus_get_addr_slot_status(&master->bus,
> > >  						i3cboardinfo->init_dyn_addr);
> > > -			if (status != I3C_ADDR_SLOT_FREE) {
> > > -				ret = -EBUSY;
> > > -				goto err_detach_devs;
> > > -			}
> > > +			if (status != I3C_ADDR_SLOT_FREE)
> > > +				return -EBUSY;
> > >  		}
> > >  
> > >  		i3cdev = i3c_master_alloc_i3c_dev(master, &info);
> > > -		if (IS_ERR(i3cdev)) {
> > > -			ret = PTR_ERR(i3cdev);
> > > -			goto err_detach_devs;
> > > -		}
> > > +		if (IS_ERR(i3cdev))
> > > +			return PTR_ERR(i3cdev);
> > >  
> > >  		i3cdev->boardinfo = i3cboardinfo;
> > >  
> > >  		ret = i3c_master_attach_i3c_dev(master, i3cdev);
> > >  		if (ret) {
> > >  			i3c_master_free_i3c_dev(i3cdev);
> > > -			goto err_detach_devs;
> > > +			return ret;
> > >  		}
> > >  	}
> > >  
> > > +	return 0;
> > > +}
> > > +
> > > +/**
> > > + * i3c_master_bus_init() - initialize an I3C bus
> > > + * @master: main master initializing the bus
> > > + *
> > > + * This function is following all initialisation steps described in the I3C
> > > + * specification:
> > > + *
> > > + * 1. Attach I2C and statically defined I3C devs to the master so that the
> > > + *    master can fill its internal device table appropriately
> > > + *
> > > + * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
> > > + *    the master controller. That's usually where the bus mode is selected
> > > + *    (pure bus or mixed fast/slow bus)
> > > + *
> > > + * 3. Instruct all devices on the bus to drop their dynamic address. This is
> > > + *    particularly important when the bus was previously configured by someone
> > > + *    else (for example the bootloader)
> > > + *
> > > + * 4. Disable all slave events.
> > > + *
> > > + * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
> > > + *    devices that have a static address
> > > + *
> > > + * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
> > > + *    remaining I3C devices
> > > + *
> > > + * Once this is done, all I3C and I2C devices should be usable.
> > > + *
> > > + * Return: a 0 in case of success, an negative error code otherwise.
> > > + */
> > > +static int i3c_master_bus_init(struct i3c_master_controller *master)
> > > +{
> > > +	struct i3c_dev_desc *i3cdev;
> > > +	int ret;
> > > +
> > > +	/*
> > > +	 * First attach all devices with static definitions provided by the
> > > +	 * FW.
> > > +	 */
> > > +	ret = i3c_master_attach_static_devs(master);
> > > +	if (ret)
> > > +		goto err_detach_devs;
> > >  	/*
> > >  	 * Now execute the controller specific ->bus_init() routine, which
> > >  	 * might configure its internal logic to match the bus limitations.
> > > @@ -1780,45 +1926,76 @@ i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev)
> > >  }
> > >  
> > >  /**
> > > - * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> > > - * @master: master used to send frames on the bus
> > > - * @addr: I3C slave dynamic address assigned to the device
> > > + * i3c_master_add_i2c_dev_locked() - add an I2C slave to the bus
> > > + * @master: master used to register I2C device
> > > + * @addr: I2C device address
> > > + * @lvr: legacy virtual register value
> > >   *
> > > - * This function is instantiating an I3C device object and adding it to the
> > > - * I3C device list. All device information are automatically retrieved using
> > > - * standard CCC commands.
> > > - *
> > > - * The I3C device object is returned in case the master wants to attach
> > > - * private data to it using i3c_dev_set_master_data().
> > > + * This function is instantiating an I2C device object and adding it to the
> > > + * I2C device list.
> > >   *
> > >   * This function must be called with the bus lock held in write mode.
> > >   *
> > >   * Return: a 0 in case of success, an negative error code otherwise.
> > >   */
> > > -int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > -				  u8 addr)
> > > +int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
> > > +				  u16 addr, u8 lvr)
> > >  {
> > > -	struct i3c_device_info info = { .dyn_addr = addr };
> > > -	struct i3c_dev_desc *newdev, *olddev;
> > > -	u8 old_dyn_addr = addr, expected_dyn_addr;
> > > -	struct i3c_ibi_setup ibireq = { };
> > > -	bool enable_ibi = false;
> > > +	enum i3c_addr_slot_status status;
> > > +	struct i2c_dev_desc *i2cdev;
> > >  	int ret;
> > >  
> > >  	if (!master)
> > >  		return -EINVAL;
> > >  
> > > -	newdev = i3c_master_alloc_i3c_dev(master, &info);
> > > -	if (IS_ERR(newdev))
> > > -		return PTR_ERR(newdev);
> > > +	status = i3c_bus_get_addr_slot_status(&master->bus,
> > > +					      addr);
> > > +	if (status != I3C_ADDR_SLOT_FREE)
> > > +		return -EBUSY;
> > >  
> > > -	ret = i3c_master_attach_i3c_dev(master, newdev);
> > > -	if (ret)
> > > +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> > > +				     I3C_ADDR_SLOT_I2C_DEV);
> > > +
> > > +	i2cdev = i3c_master_alloc_i2c_dev_no_boardinfo(master, addr, lvr);
> > > +
> > > +	if (IS_ERR(i2cdev)) {
> > > +		ret = PTR_ERR(i2cdev);
> > > +		goto err_free_dev;
> > > +	}
> > > +
> > > +	i2cdev->boardinfo = i3c_master_find_i2c_boardinfo(master, addr, lvr);
> > > +
> > > +	ret = i3c_master_attach_i2c_dev(master, i2cdev);
> > > +
> > > +	if (ret) {
> > > +		ret = PTR_ERR(i2cdev);
> > >  		goto err_free_dev;
> > > +	}
> > > +
> > > +	return 0;
> > > +
> > > +err_free_dev:
> > > +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> > > +				     I3C_ADDR_SLOT_FREE);
> > > +	i3c_master_free_i2c_dev(i2cdev);
> > > +
> > > +	return ret;
> > > +}
> > > +EXPORT_SYMBOL_GPL(i3c_master_add_i2c_dev_locked);
> > > +
> > > +static int
> > > +i3c_master_retrieve_info_and_reuse(struct i3c_master_controller *master,
> > > +				   struct i3c_dev_desc *newdev)
> > > +{
> > > +	struct i3c_dev_desc *olddev;
> > > +	u8 old_dyn_addr = newdev->info.dyn_addr, expected_dyn_addr;
> > > +	struct i3c_ibi_setup ibireq = { };
> > > +	bool enable_ibi = false;
> > > +	int ret;
> > >  
> > >  	ret = i3c_master_retrieve_dev_info(newdev);
> > >  	if (ret)
> > > -		goto err_detach_dev;
> > > +		return ret;
> > >  
> > >  	olddev = i3c_master_search_i3c_dev_duplicate(newdev);
> > >  	if (olddev) {
> > > @@ -1857,7 +2034,7 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > >  
> > >  	ret = i3c_master_reattach_i3c_dev(newdev, old_dyn_addr);
> > >  	if (ret)
> > > -		goto err_detach_dev;
> > > +		return ret;
> > >  
> > >  	/*
> > >  	 * Depending on our previous state, the expected dynamic address might
> > > @@ -1920,6 +2097,50 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > >  	}
> > >  
> > >  	return 0;
> > > +}
> > > +
> > > +/**
> > > + * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> > > + * @master: master used to send frames on the bus
> > > + * @addr: I3C slave dynamic address assigned to the device
> > > + *
> > > + * This function is instantiating an I3C device object and adding it to the
> > > + * I3C device list. All device information are automatically retrieved using
> > > + * standard CCC commands.
> > > + *
> > > + * The I3C device object is returned in case the master wants to attach
> > > + * private data to it using i3c_dev_set_master_data().
> > > + *
> > > + * This function must be called with the bus lock held in write mode.
> > > + *
> > > + * Return: a 0 in case of success, an negative error code otherwise.
> > > + */
> > > +int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > +				  u8 addr)
> > > +{
> > > +	struct i3c_device_info info = { .dyn_addr = addr };
> > > +	struct i3c_dev_desc *newdev;
> > > +	int ret;
> > > +
> > > +	if (!master)
> > > +		return -EINVAL;
> > > +
> > > +	newdev = i3c_master_alloc_i3c_dev(master, &info);
> > > +	if (IS_ERR(newdev))
> > > +		return PTR_ERR(newdev);
> > > +
> > > +	ret = i3c_master_attach_i3c_dev(master, newdev);
> > > +	if (ret)
> > > +		goto err_free_dev;
> > > +
> > > +	if (i3c_master_owns_bus(master)) {
> > > +		ret = i3c_master_retrieve_info_and_reuse(master, newdev);
> > > +		if (ret)
> > > +			goto err_detach_dev;
> > > +	} else
> > > +		master->want_to_acquire_bus = true;
> > > +
> > > +	return 0;
> > >  
> > >  err_detach_dev:
> > >  	if (newdev->dev && newdev->dev->desc)
> > > @@ -2101,11 +2322,15 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
> > >  	}
> > >  
> > >  	i3c_bus_normaluse_lock(&master->bus);
> > > +	ret = i3c_master_acquire_bus_ownership(master);
> > > +	if (ret)
> > > +		goto err_unlock_bus;
> > >  	dev = i3c_master_find_i2c_dev_by_addr(master, addr);
> > >  	if (!dev)
> > >  		ret = -ENOENT;
> > >  	else
> > >  		ret = master->ops->i2c_xfers(dev, xfers, nxfers);
> > > +err_unlock_bus:
> > >  	i3c_bus_normaluse_unlock(&master->bus);
> > >  
> > >  	return ret ? ret : nxfers;
> > > @@ -2144,9 +2369,12 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
> > >  	 * We silently ignore failures here. The bus should keep working
> > >  	 * correctly even if one or more i2c devices are not registered.
> > >  	 */
> > > -	i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
> > > +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> > > +		if (!i2cdev->boardinfo)
> > > +			continue;
> > >  		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
> > >  
> > > +	}
> > >  	return 0;
> > >  }
> > >  
> > > @@ -2385,9 +2613,76 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
> > >  	     !ops->recycle_ibi_slot))
> > >  		return -EINVAL;
> > >  
> > > +	/*
> > > +	 * If mastership request is supported, we also need hooks to control
> > > +	 * when mastership request can occur by enabling/disabling the event.
> > > +	 */
> > > +	if (ops->request_mastership &&
> > > +	    (!ops->enable_mr_events || !ops->disable_mr_events))
> > > +		return -EINVAL;
> > >  	return 0;
> > >  }
> > >  
> > > +static void i3c_master_register_new_devs(struct i3c_master_controller *master)
> > > +{
> > > +	/*
> > > +	 * We can register devices received from master by DEFSLVS.
> > > +	 */
> > > +	i3c_bus_normaluse_lock(&master->bus);
> > > +	i3c_master_register_new_i3c_devs(master);
> > > +	i3c_master_register_new_i2c_devs(master);
> > > +	i3c_bus_normaluse_unlock(&master->bus);
> > > +}
> > > +
> > > +/**
> > > + * i3c_master_bus_takeover() - register new I3C devices on bus takeover
> > > + * @master: master used to send frames on the bus
> > > + *
> > > + * This function is useful when devices were not added
> > > + * during initialization or when new device joined the bus
> > > + * which wasn't under our control.
> > > + */
> > > +void i3c_master_bus_takeover(struct i3c_master_controller *master)
> > > +{
> > > +	struct i3c_dev_desc *i3cdev, *i3ctmp;
> > > +	int ret;
> > > +
> > > +	master->want_to_acquire_bus = false;
> > 
> > Can you explain the usage of this variable?
> > 
> 
> The idea of this was to let HC know that we want to acquire the bus after
> ENEC(MR) received in slave mode.

With the logic that I proposed you don't need this. When received ENEC 
you will try to get the bus ownership if HC not fully initialized or have 
DEFSLVS to add, otherwise you don't need to get the bus ownership.

> 
> > > +
> > > +	if (!master->init_done)
> > > +		return;
> > > +
> > > +	i3c_bus_maintenance_lock(&master->bus);
> > > +	master->ops->populate_bus(master);
> > > +
> > > +	list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c,
> > > +				 common.node) {
> > > +		if (i3cdev->info.pid)
> > > +			continue;
> > > +
> > > +		ret = i3c_master_retrieve_info_and_reuse(master, i3cdev);
> > > +		if (ret) {
> > > +			if (i3cdev->dev && i3cdev->dev->desc)
> > > +				i3cdev->dev->desc = NULL;
> > > +
> > > +			i3c_master_detach_i3c_dev(i3cdev);
> > > +		}
> > > +	}
> > > +
> > > +	/*
> > > +	 * If current master finished bus initialization properly, we can
> > > +	 * enable Mastership event.
> > > +	 */
> > > +	ret = i3c_master_enable_mr_events_locked(master);
> > > +	if (ret)
> > > +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> > > +
> > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > +
> > > +	i3c_master_register_new_devs(master);
> > > +}
> > > +EXPORT_SYMBOL_GPL(i3c_master_bus_takeover);
> > > +
> > >  /**
> > >   * i3c_master_init() - initializes all the structures required by I3C master
> > >   * @master: master used to send frames on the bus
> > > @@ -2417,9 +2712,6 @@ int i3c_master_init(struct i3c_master_controller *master,
> > >  	struct i2c_dev_boardinfo *i2cbi;
> > >  	int ret;
> > >  
> > > -	/* We do not support secondary masters yet. */
> > > -	if (secondary)
> > > -		return -ENOTSUPP;
> > >  
> > >  	ret = i3c_master_check_ops(ops);
> > >  	if (ret)
> > > @@ -2432,6 +2724,7 @@ int i3c_master_init(struct i3c_master_controller *master,
> > >  	master->dev.release = i3c_masterdev_release;
> > >  	master->ops = ops;
> > >  	master->secondary = secondary;
> > > +	master->want_to_acquire_bus = secondary;
> > >  	INIT_LIST_HEAD(&master->boardinfo.i2c);
> > >  	INIT_LIST_HEAD(&master->boardinfo.i3c);
> > >  
> > > @@ -2488,6 +2781,92 @@ void i3c_master_cleanup(struct i3c_master_controller *master)
> > >  EXPORT_SYMBOL_GPL(i3c_master_cleanup);
> > >  
> > >  /**
> > > + * i3c_secondary_master_register() - register an secondary I3C master
> > > + * @master: master used to send frames on the bus
> > > + * @info: master info, describes this device
> > > + *
> > > + * This function takes care of everything for you:
> > > + *
> > > + * - updates this master info
> > > + * - registers the I2C adapter
> > > + * - if possible, populates the bus with devices received by DEFSLVS
> > > + *   command
> > > + *
> > > + * Return: 0 in case of success, a negative error code otherwise.
> > > + */
> > > +int i3c_secondary_master_register(struct i3c_master_controller *master,
> > > +				  struct i3c_device_info *info)
> > > +{
> > > +	int ret;
> > > +
> > > +	ret = i3c_master_set_info(master, info, master->secondary);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	ret = master->ops->bus_init(master);
> > > +	if (ret)
> > > +		return ret;
> > 
> > At this point you don't have enough information to do the bus 
> > initialization.
> > 
> 
> Actually, current ->bus_init() implementations (in CDNS and DW) does not
> initialize the bus. We are just setting the mode, configuring some init values
> in the registers and enabling the core. Maybe we should rename it?

The name for me its ok. My point was that when you call 
i3c_secondary_master_register() in CDNS you don't have yet DEFSLVS 
information.

> 
> > > +
> > > +	ret = device_add(&master->dev);
> > > +	if (ret)
> > > +		return -1;
> > > +
> > > +	/*
> > > +	 * Expose our I3C bus as an I2C adapter so that I2C devices are exposed
> > > +	 * through the I2C subsystem.
> > > +	 */
> > > +	ret = i3c_master_i2c_adapter_init(master);
> > > +	if (ret)
> > > +		goto err_del_dev;
> > > +
> > > +	i3c_bus_maintenance_lock(&master->bus);
> > > +	/*
> > > +	 * If possible, request mastership and try to populate the bus.
> > > +	 */
> > > +	ret = i3c_master_request_mastership_locked(master);
> > > +	if (ret)
> > > +		dev_warn(&master->dev,
> > > +			 "Mastership failed at init time (ret = %i)", ret);
> > > +
> > > +	/*
> > > +	 * No matter if mastership takeover passed or not, add partialy
> > > +	 * discovered devices. We can register them when ENEC(MR) is enabled.
> > > +	 */
> > > +	master->ops->populate_bus(master);
> > > +
> > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > +
> > > +	/*
> > > +	 * We're done initializing the bus and the controller, we can now
> > > +	 * register I3C devices obtained by DEFSLVS.
> > > +	 */
> > > +	master->init_done = true;
> > > +	i3c_master_register_new_devs(master);
> > > +
> > > +	/*
> > > +	 * If we are owning the bus, enable ENEC(MR) to let other masters
> > > +	 * initialize their bus.
> > > +	 */
> > > +	if (i3c_master_owns_bus(master)) {
> > > +		i3c_bus_maintenance_lock(&master->bus);
> > > +		ret = i3c_master_enable_mr_events_locked(master);
> > > +		i3c_bus_maintenance_unlock(&master->bus);
> > > +		if (ret)
> > > +			dev_warn(&master->dev,
> > > +				 "ENEC(MR) failed (ret = %i)", ret);
> > > +	}
> > > +
> > > +
> > > +	return 0;
> > > +
> > > +err_del_dev:
> > > +	device_del(&master->dev);
> > > +
> > > +	return ret;
> > > +}
> > > +EXPORT_SYMBOL_GPL(i3c_secondary_master_register);
> > > +
> > > +/**
> > >   * i3c_master_register() - register an primary I3C master
> > >   * @master: master used to send frames on the bus
> > >   * @info: master info, describes this device
> > > @@ -2509,7 +2888,6 @@ int i3c_master_register(struct i3c_master_controller *master,
> > >  	ret = i3c_master_set_info(master, info, master->secondary);
> > >  	if (ret)
> > >  		return ret;
> > > -
> > >  	ret = i3c_master_bus_init(master);
> > >  	if (ret)
> > >  		return ret;
> > > @@ -2535,6 +2913,16 @@ int i3c_master_register(struct i3c_master_controller *master,
> > >  	i3c_master_register_new_i3c_devs(master);
> > >  	i3c_bus_normaluse_unlock(&master->bus);
> > >  
> > > +	/*
> > > +	 * Enable ENEC(MR) and let other masters request mastership
> > > +	 * and initialize their bus.
> > > +	 */
> > > +	i3c_bus_maintenance_lock(&master->bus);
> > > +	ret = i3c_master_enable_mr_events_locked(master);
> > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > +	if (ret)
> > > +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> > > +
> > >  	return 0;
> > >  
> > >  err_del_dev:
> > > @@ -2548,6 +2936,29 @@ int i3c_master_register(struct i3c_master_controller *master,
> > >  EXPORT_SYMBOL_GPL(i3c_master_register);
> > >  
> > >  /**
> > > + * i3c_master_mastership_ack() - acknowledges bus takeover.
> > > + * @master: master used to send frames on the bus
> > > + * @addr: I3C device address
> > > + *
> > > + * This function acknowledges bus takeover.
> > > + *
> > > + * Return: 0 in case of success, a negative error code otherwise.
> > > + */
> > > +int i3c_master_mastership_ack(struct i3c_master_controller *master,
> > > +			      u8 addr)
> > > +{
> > > +	int ret;
> > > +
> > > +	i3c_bus_maintenance_lock(&master->bus);
> > > +	ret = i3c_master_get_accmst_locked(master, addr);
> > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > +
> > > +	return ret;
> > > +}
> > > +EXPORT_SYMBOL_GPL(i3c_master_mastership_ack);
> > > +
> > > +
> > > +/**
> > >   * i3c_master_unregister() - unregister an I3C master
> > >   * @master: master used to send frames on the bus
> > >   *
> > > @@ -2557,6 +2968,9 @@ EXPORT_SYMBOL_GPL(i3c_master_register);
> > >   */
> > >  int i3c_master_unregister(struct i3c_master_controller *master)
> > >  {
> > > +	i3c_bus_maintenance_lock(&master->bus);
> > > +	i3c_master_disable_mr_events(master);
> > > +	i3c_bus_maintenance_unlock(&master->bus);
> > >  	i3c_master_i2c_adapter_cleanup(master);
> > >  	i3c_master_unregister_i3c_devs(master);
> > >  	i3c_master_bus_cleanup(master);
> > > diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
> > > index e089771..6ac9b46 100644
> > > --- a/include/linux/i3c/master.h
> > > +++ b/include/linux/i3c/master.h
> > > @@ -421,6 +421,26 @@ struct i3c_bus {
> > >   *		      for a future IBI
> > >   *		      This method is mandatory only if ->request_ibi is not
> > >   *		      NULL.
> > > + * @request_mastership: requests bus mastership. Mastership is requested
> > > + *                      automatically when device driver wants to transfer
> > > + *                      data using a master that does not currently
> > > + *                      owns the bus.
> > > + * @enable_mr_events: enable the Mastership event. Master driver can prepare
> > > + *                    its internal state to be ready for incoming mastership
> > > + *                    requests and then should send ENEC(MR) command to let
> > > + *                    other masters take control over the bus.
> > > + * @disable_mr_events: disable the Mastership event. Master driver should
> > > + *                     immediately send DISEC(MR) command and can perform other
> > > + *                     operations. For example, recycle IBI slot if used before
> > > + *                     for MR event.
> > > + * @populate_pus: populates the bus. Called after bus takeover. Secondary
> > > + *                master can't perform DAA procedure. This function allows to
> > > + *                update devices received from previous bus owner in DEFSLVS
> > > + *                command. Useful also when new device joins the bus controlled
> > > + *                by secondary master, main master will be able to add
> > > + *                this device after mastership takeover. Driver should also
> > > + *		  update bus mode when I2C device is on the bus.
> > > + *
> > >   */
> > >  struct i3c_master_controller_ops {
> > >  	int (*bus_init)(struct i3c_master_controller *master);
> > > @@ -447,6 +467,10 @@ struct i3c_master_controller_ops {
> > >  	int (*disable_ibi)(struct i3c_dev_desc *dev);
> > >  	void (*recycle_ibi_slot)(struct i3c_dev_desc *dev,
> > >  				 struct i3c_ibi_slot *slot);
> > > +	int (*request_mastership)(struct i3c_master_controller *master);
> > > +	int (*enable_mr_events)(struct i3c_master_controller *master);
> > > +	int (*disable_mr_events)(struct i3c_master_controller *master);
> > > +	int (*populate_bus)(struct i3c_master_controller *master);
> > >  };
> > >  
> > >  /**
> > > @@ -488,6 +512,7 @@ struct i3c_master_controller {
> > >  	} boardinfo;
> > >  	struct i3c_bus bus;
> > >  	struct workqueue_struct *wq;
> > > +	bool want_to_acquire_bus;
> > >  };
> > >  
> > >  /**
> > > @@ -526,6 +551,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master);
> > >  int i3c_master_get_free_addr(struct i3c_master_controller *master,
> > >  			     u8 start_addr);
> > >  
> > > +int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
> > > +				  u16 addr, u8 lvr);
> > >  int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > >  				  u8 addr);
> > >  int i3c_master_do_daa(struct i3c_master_controller *master);
> > > @@ -535,9 +562,14 @@ int i3c_master_init(struct i3c_master_controller *master,
> > >  		    const struct i3c_master_controller_ops *ops,
> > >  		    bool secondary);
> > >  void i3c_master_cleanup(struct i3c_master_controller *master);
> > > +int i3c_secondary_master_register(struct i3c_master_controller *master,
> > > +				  struct i3c_device_info *info);
> > >  int i3c_master_register(struct i3c_master_controller *master,
> > >  			struct i3c_device_info *info);
> > >  int i3c_master_unregister(struct i3c_master_controller *master);
> > > +int i3c_master_mastership_ack(struct i3c_master_controller *master,
> > > +			      u8 addr);
> > > +void i3c_master_bus_takeover(struct i3c_master_controller *master);
> > >  int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode);
> > >  
> > >  /**
> > > @@ -648,7 +680,5 @@ void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot);
> > >  
> > >  struct i3c_ibi_slot *i3c_master_get_free_ibi_slot(struct i3c_dev_desc *dev);
> > >  
> > > -void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> > > -void i3c_bus_maintenance_unlock(struct i3c_bus *bus);
> > >  
> > >  #endif /* I3C_MASTER_H */
> > > -- 
> > > 2.4.5
> > 
> > In generally I found this intrusive for the current eco system.
> > 
> > I propose the following:
> > 1 - Keep the function i3c_master_register() as is and go out before 
> 
> We had that version previously. We decided to split it.

You just need to split the secondary master part from it. So you can go 
out before i3c_master_bus_init() and keep the same function.

Them use i3c_secondary_master_register() when received DEFSLVS or ENEC 
MR.

> 
> > i3c_master_bus_init() if secondary master.
> > @Boris Brezillon is it possible to replace device_initialize() device_add() with device_register()?
> > 
> > 2 - When received DEFSLVS commands add devices to a link list like 
> > boardinfo.
> 
> If DEFSLVS received devices are partialy added at init time.
> 
> >   Get bus ownership if there is DEFSLVS to add or secondary master not 
> > initialized. 
> > 
> > 3 - When received ENEC MR
> 
> I thought it works like that :-) When ENEC(MR) received, HC driver adds devices
> from DEFSLVS frame,

Yes, but in your case the logic is in HC. Let the subsystem do that task 
when you switch the role.
I think you did that in v1 or v2.

> 
> >   Get bus ownership if there is DEFSLVS to add or secondary master not 
> > initialized.
> > 
> > 4 - When secondary master became current master.
> 
> and calls i3c_master_bus_takeover() to let subsystem gather device information
> and register them.

It  is not clear to me if it is already the current master.

> 
> >   Attach new devices to the host controller and retrieve device info 
> > (same logic as in i3c_master_add_i3c_dev_locked).
> > 
> > With this approach on HC side you just need to add the secondary master 
> > stuff without changing the current code and leave for the subsystem the 
> > responsible to manage all these secondary master task.
> 
> This may be difficult for some controllers, depends where DEFSLVS device
> information is stored.

That is the main reason I want pass DEFSLVS to a list in the subsystem.
I think it will be common to everyone receive a notification that DEFSLVS 
arrived.

> I also cannot find information about that part in
> MIPI I3C HCI specification. This part can be vendor specific. What do you
> think?

It is not defined int v1.0

> 
> > 
> > Let me know if this works for you.
> > 
> > 
> > Best regards,
> > Vitor Soares
> 
> -- 
> -- 
> Przemyslaw Gaj

Best regards,
Vitor Soares


_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem
  2019-07-11 10:11       ` Vitor Soares
@ 2019-07-12 10:10         ` Przemyslaw Gaj
  2019-07-12 11:28           ` Vitor Soares
  0 siblings, 1 reply; 21+ messages in thread
From: Przemyslaw Gaj @ 2019-07-12 10:10 UTC (permalink / raw)
  To: Vitor Soares; +Cc: linux-i3c, agolec, rafalc, bbrezillon

Hi Vitor,

The 07/11/2019 10:11, Vitor Soares wrote:
> EXTERNAL MAIL
> 
> 
> From: Przemyslaw Gaj <pgaj@cadence.com>
> Date: Thu, Jul 11, 2019 at 06:28:18
> 
> > Hi Vitor,
> > 
> > The 07/10/2019 18:04, Vitor Soares wrote:
> > > EXTERNAL MAIL
> > > 
> > > 
> > > From: Przemyslaw Gaj <pgaj@cadence.com>
> > > Date: Sat, Jun 22, 2019 at 21:55:02
> > > 
> > > > This patch adds support for mastership request to I3C subsystem.
> > > > 
> > > > Mastership event is enabled globally.
> > > > 
> > > > Mastership is requested automatically when device driver
> > > > tries to transfer data using master controller in slave mode.
> > > > 
> > > > There is still some limitation:
> > > > - I2C devices are registered on secondary master side if boardinfo
> > > > entry matching the info transmitted through the DEFSLVS frame.
> > > > 
> > > > Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
> > > > 
> > > > ---
> > > > 
> > > > Main changes between v4 and v5:
> > > > - Add function to test if master owns the bus
> > > > - Add i3c_secondary_master_register() function
> > > > - Add populate_bus() hook to populate the bus after mastership takeover
> > > 
> > > For me this task is for the sub-system not the host controller.
> > > 
> > 
> > I'm not sure where device information is stored in DW controller but in CDNS
> > controller DEFSLVS frame is processed in the device and the only thing I got is
> > information that DEFSLVS came in. 
> 
> When you receive this notification you can add the device to subsystem to 
> be initialized later when get bus ownership.

I added this hook mostly because we have to lock the bus during devices
addition. If we pass DEFSLVS devices information to the system in some
structure, we should be ok. We can lock the bus in the framework and register
all the devices. But I still don't feel this is good solution, I'll have to
do the job once again which HW did before

@Boris, what do you think about that?

> 
> > I need to inform subsystem that there are new
> > device (if any).
> > I remember we talkad about that already, you have access to
> > DEFSLVS information directly, correct?
> 
> I can process it in the HC driver, but my point is that I want to rely it 
> to the subsystem the bus population with the function already present.
> 

So, do you want to pack those informations back to i3c_ccc_defslvs and pass to
the subsystem?

> > 
> > > > - Rework device information retrieval to allow adding partialy discovered
> > > > devices
> > > > 
> > > > Main changes between v3 and v4:
> > > > - Add i3c_master_acquire_bus_ownership to acquire the bus
> > > > - Refactored the code
> > > > 
> > > > Main changes between v2 and v3:
> > > > - Add i3c_bus_downgrade_maintenance_lock() for downgrading the bus
> > > > lock from maintenance to normal use
> > > > - Add additional fields to i2c_dev_desc for DEFSLVS purpose (addr, lvr)
> > > > - Add i3c_master_register_new_i2c_devs() function to register I2C devices
> > > > - Reworked I2C devices registration on secondary master side
> > > > 
> > > > Changes in v2:
> > > > - Add mastership disable event hook
> > > > - Changed name of mastership enable event hook
> > > > - Add function to test if master owns the bus
> > > > - Removed op_mode
> > > > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > > > pass full i3c_device_info
> > > > - Changed name of mastership enable event hook
> > > > - Add function to test if master owns the bus
> > > > - Removed op_mode
> > > > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > > > pass full i3c_device_info
> > > > - Removed redundant DEFSLVS command before GETACCMST
> > > > - Add i3c_master_bus_takeover function. There is a need to lock
> > > > the bus before adding devices and no matter of the controller
> > > > devices have to be added after mastership takeover.
> > > > - Add device registration during initialization on secondary master
> > > > side. Devices received by DEFSLVS (if occured). If not, device
> > > > initialization is deffered untill next mastership request.
> > > > ---
> > > >  drivers/i3c/device.c       |  26 ++
> > > >  drivers/i3c/internals.h    |   4 +
> > > >  drivers/i3c/master.c       | 588 ++++++++++++++++++++++++++++++++++++++-------
> > > >  include/linux/i3c/master.h |  34 ++-
> > > >  4 files changed, 563 insertions(+), 89 deletions(-)
> > > > 
> > > > diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
> > > > index 69cc040..b60f637 100644
> > > > --- a/drivers/i3c/device.c
> > > > +++ b/drivers/i3c/device.c
> > > > @@ -43,7 +43,13 @@ int i3c_device_do_priv_xfers(struct i3c_device *dev,
> > > >  	}
> > > >  
> > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > +	if (ret)
> > > > +		goto err_unlock_bus;
> > > > +
> > > >  	ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
> > > > +
> > > > +err_unlock_bus:
> > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > >  
> > > >  	return ret;
> > > > @@ -114,11 +120,17 @@ int i3c_device_enable_ibi(struct i3c_device *dev)
> > > >  	int ret = -ENOENT;
> > > >  
> > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > +	if (ret)
> > > > +		goto err_unlock_bus;
> > > > +
> > > >  	if (dev->desc) {
> > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > >  		ret = i3c_dev_enable_ibi_locked(dev->desc);
> > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > >  	}
> > > > +
> > > > +err_unlock_bus:
> > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > >  
> > > >  	return ret;
> > > > @@ -145,11 +157,17 @@ int i3c_device_request_ibi(struct i3c_device *dev,
> > > >  		return -EINVAL;
> > > >  
> > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > +	if (ret)
> > > > +		goto err_unlock_bus;
> > > > +
> > > >  	if (dev->desc) {
> > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > >  		ret = i3c_dev_request_ibi_locked(dev->desc, req);
> > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > >  	}
> > > > +
> > > > +err_unlock_bus:
> > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > >  
> > > >  	return ret;
> > > > @@ -166,12 +184,20 @@ EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
> > > >   */
> > > >  void i3c_device_free_ibi(struct i3c_device *dev)
> > > >  {
> > > > +	int ret;
> > > > +
> > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > +	if (ret)
> > > > +		goto err_unlock_bus;
> > > > +
> > > >  	if (dev->desc) {
> > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > >  		i3c_dev_free_ibi_locked(dev->desc);
> > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > >  	}
> > > > +
> > > > +err_unlock_bus:
> > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > >  }
> > > >  EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
> > > > diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
> > > > index 86b7b44..cdfc5bf 100644
> > > > --- a/drivers/i3c/internals.h
> > > > +++ b/drivers/i3c/internals.h
> > > > @@ -14,6 +14,10 @@ extern struct bus_type i3c_bus_type;
> > > >  
> > > >  void i3c_bus_normaluse_lock(struct i3c_bus *bus);
> > > >  void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
> > > > +void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> > > > +void i3c_bus_maintenance_unlock(struct i3c_bus *bus);
> > > 
> > > These function are static.
> > > 
> > 
> > I forgot to revert that change to previous state.
> > 
> > > > +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master);
> > > > +
> > > 
> > > What do you think to pass this logic to master.c?
> > > 
> > 
> > Isn't it there?
> 
> I meant make it static and remove its call from device.c.
> 
> > 
> > > >  
> > > >  int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
> > > >  				 struct i3c_priv_xfer *xfers,
> > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> > > > index cbace14..3b44e66 100644
> > > > --- a/drivers/i3c/master.c
> > > > +++ b/drivers/i3c/master.c
> > > > @@ -93,6 +93,18 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
> > > >  	up_read(&bus->lock);
> > > >  }
> > > >  
> > > > +/*
> > > > + * i3c_bus_downgrade_maintenance_lock - Downgrade the bus lock to normal
> > > > + * operation
> > > > + *
> > > > + * Should be called when a maintenance operation is done and normal
> > > > + * operation is planned. See i3c_bus_maintenance_lock() and
> > > > + * i3c_bus_normaluse_lock() for more details.
> > > > + */
> > > > +static void i3c_bus_downgrade_maintenance_lock(struct i3c_bus *bus)
> > > > +{
> > > > +	downgrade_write(&bus->lock);
> > > > +}
> > > >  static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
> > > >  {
> > > >  	return container_of(dev, struct i3c_master_controller, dev);
> > > > @@ -341,6 +353,22 @@ static int i3c_device_probe(struct device *dev)
> > > >  	return driver->probe(i3cdev);
> > > >  }
> > > >  
> > > > +static int
> > > > +i3c_master_enable_mr_events_locked(struct i3c_master_controller *master)
> > > > +{
> > > > +	if (!master->ops->enable_mr_events)
> > > > +		return -ENOTSUPP;
> > > > +
> > > > +	return master->ops->enable_mr_events(master);
> > > > +}
> > > > +
> > > > +static void i3c_master_disable_mr_events(struct i3c_master_controller *master)
> > > > +{
> > > > +	if (!master->ops->disable_mr_events)
> > > > +		return;
> > > > +
> > > > +	master->ops->disable_mr_events(master);
> > > > +}
> > > 
> > > Add new line.
> > > 
> > > It is not clear to me what you expect with these functions. Do you want 
> > > to enable MR from all devices? Just some of them? How do you decide which 
> > > secondary masters are allow earn the bus ownership?
> > > 
> > 
> > We discussed this also. For now, we enable ENEC for all masters on the bus, we
> > can change it later if needed. 
> 
> I would say to expand the current ibi framework to accommodate MR and

Can you tell something more here? What benefits you see

> also add platform entry to allow secondary masters on the bus.

This is something we can consider, to select devices which can request
mastership. But I don't see the problem adding that later also.

> 
> > Also, priority level is encoded in slave address
> > so current master will give the control to the master with lower address first.
> > It shouldn't be a problem.
> 
> You can have security issues and the devices on the bus might not be 
> prepared to work in multi-master environment.

I don't get it, can you explan what do you mean? Which devices might not be
prapared to work in multi-master environment, slaves? Key feature of I3C is
multi-master capability. Mastership request should also be transparent for pure
slaves on the bus. Of course, secondary masters should work in multi-master
configuration

> 
> > 
> > > >  static int i3c_device_remove(struct device *dev)
> > > >  {
> > > >  	struct i3c_device *i3cdev = dev_to_i3cdev(dev);
> > > > @@ -462,6 +490,42 @@ static int i3c_bus_init(struct i3c_bus *i3cbus)
> > > >  	return 0;
> > > >  }
> > > >  
> > > > +static int
> > > > +i3c_master_request_mastership_locked(struct i3c_master_controller *master)
> > > > +{
> > > > +	if (WARN_ON(master->init_done &&
> > > > +	    !rwsem_is_locked(&master->bus.lock)))
> > > > +		return -EINVAL;
> > > > +
> > > > +	if (!master->ops->request_mastership)
> > > > +		return -ENOTSUPP;
> > > > +
> > > > +	return master->ops->request_mastership(master);
> > > > +}
> > > > +
> > > > +static int i3c_master_owns_bus(struct i3c_master_controller *master)
> > > > +{
> > > > +	return (master->bus.cur_master == master->this);
> > > > +}
> > > > +
> > > > +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master)
> > > > +{
> > > > +	int ret;
> > > > +
> > > > +	if (!i3c_master_owns_bus(master)) {
> > > > +		i3c_bus_normaluse_unlock(&master->bus);
> > > > +		i3c_bus_maintenance_lock(&master->bus);
> > > > +
> > > > +		ret = i3c_master_request_mastership_locked(master);
> > > > +		if (ret) {
> > > > +			i3c_bus_maintenance_unlock(&master->bus);
> > > > +			return ret;
> > > > +		}
> > > > +		i3c_bus_downgrade_maintenance_lock(&master->bus);
> > > > +	}
> > > > +
> > > > +	return 0;
> > > > +}
> > > >  static const char * const i3c_bus_mode_strings[] = {
> > > >  	[I3C_BUS_MODE_PURE] = "pure",
> > > >  	[I3C_BUS_MODE_MIXED_FAST] = "mixed-fast",
> > > > @@ -636,6 +700,22 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
> > > >  	return dev;
> > > >  }
> > > >  
> > > > +static struct i2c_dev_desc *
> > > > +i3c_master_alloc_i2c_dev_no_boardinfo(struct i3c_master_controller *master,
> > > > +				      u16 addr, u8 lvr)
> > > 
> > > u8 addr.
> > > 
> > 
> > Originaly I2C address is u16 but we can change it as we know DEFSLVS does not
> > support 10bit addresses.
> > 
> > > > +{
> > > > +	struct i2c_dev_desc *dev;
> > > > +
> > > > +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> > > > +	if (!dev)
> > > > +		return ERR_PTR(-ENOMEM);
> > > > +
> > > > +	dev->common.master = master;
> > > > +	dev->addr = addr;
> > > > +	dev->lvr = lvr;
> > > > +
> > > > +	return dev;
> > > > +}
> > > >  static void *i3c_ccc_cmd_dest_init(struct i3c_ccc_cmd_dest *dest, u8 addr,
> > > >  				   u16 payloadlen)
> > > >  {
> > > > @@ -705,6 +785,8 @@ i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master,
> > > >  	struct i2c_dev_desc *dev;
> > > >  
> > > >  	i3c_bus_for_each_i2cdev(&master->bus, dev) {
> > > > +		if (!dev->boardinfo)
> > > > +			continue;
> > > >  		if (dev->boardinfo->base.addr == addr)
> > > >  			return dev;
> > > >  	}
> > > > @@ -1478,7 +1560,8 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
> > > >  		return;
> > > >  
> > > >  	i3c_bus_for_each_i3cdev(&master->bus, desc) {
> > > > -		if (desc->dev || !desc->info.dyn_addr || desc == master->this)
> > > > +		if (desc->dev || !desc->info.dyn_addr ||
> > > > +		    desc == master->this || !desc->info.pid)
> > > >  			continue;
> > > >  
> > > >  		desc->dev = kzalloc(sizeof(*desc->dev), GFP_KERNEL);
> > > > @@ -1504,6 +1587,69 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
> > > >  	}
> > > >  }
> > > >  
> > > > +static struct i2c_dev_boardinfo *
> > > > +i3c_master_find_i2c_boardinfo(const struct i3c_master_controller *master,
> > > > +			      u16 addr, u8 lvr)
> > > 
> > > Same.
> > > 
> > 
> > Same :-)
> > 
> > > > +{
> > > > +	struct i2c_dev_boardinfo *i2cboardinfo;
> > > > +
> > > > +	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
> > > > +		if (i2cboardinfo->base.addr == addr &&
> > > > +		    i2cboardinfo->lvr == lvr)
> > > > +			return i2cboardinfo;
> > > > +	}
> > > > +
> > > > +	return NULL;
> > > > +}
> > > > +
> > > > +static void
> > > > +i3c_master_register_new_i2c_devs(struct i3c_master_controller *master)
> > > > +{
> > > > +	struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
> > > > +	struct i2c_dev_desc *i2cdev;
> > > > +
> > > > +	if (!master->init_done)
> > > > +		return;
> > > > +
> > > > +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> > > > +
> > > > +		if (i2cdev->dev)
> > > > +			continue;
> > > > +
> > > > +		if (!i2cdev->boardinfo)
> > > > +			continue;
> > > > +
> > > > +		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
> > > > +	}
> > > > +}
> > > > +
> > > > +static int i3c_master_get_accmst_locked(struct i3c_master_controller *master,
> > > > +					u8 addr)
> > > > +{
> > > > +	struct i3c_ccc_getaccmst *accmst;
> > > > +	struct i3c_ccc_cmd_dest dest;
> > > > +	struct i3c_ccc_cmd cmd;
> > > > +	int ret;
> > > > +
> > > > +	accmst = i3c_ccc_cmd_dest_init(&dest, addr, sizeof(*accmst));
> > > > +	if (!accmst)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETACCMST, &dest, 1);
> > > > +
> > > > +	ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
> > > > +	if (ret)
> > > > +		goto out;
> > > > +
> > > > +	if (dest.payload.len != sizeof(*accmst))
> > > > +		ret = -EIO;
> > > > +
> > > > +out:
> > > > +	i3c_ccc_cmd_dest_cleanup(&dest);
> > > > +
> > > > +	return ret;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(i3c_master_get_accmst_locked);
> > > >  /**
> > > >   * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
> > > >   * @master: master doing the DAA
> > > > @@ -1548,10 +1694,6 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
> > > >  	if (!i3c_bus_dev_addr_is_avail(&master->bus, info->dyn_addr))
> > > >  		return -EINVAL;
> > > >  
> > > > -	if (I3C_BCR_DEVICE_ROLE(info->bcr) == I3C_BCR_I3C_MASTER &&
> > > > -	    master->secondary)
> > > > -		return -EINVAL;
> > > > -
> > > >  	if (master->this)
> > > >  		return -EINVAL;
> > > >  
> > > > @@ -1560,7 +1702,8 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
> > > >  		return PTR_ERR(i3cdev);
> > > >  
> > > >  	master->this = i3cdev;
> > > > -	master->bus.cur_master = master->this;
> > > > +	if (!secondary)
> > > > +		master->bus.cur_master = master->this;
> > > >  
> > > >  	ret = i3c_master_attach_i3c_dev(master, i3cdev);
> > > >  	if (ret)
> > > > @@ -1601,37 +1744,7 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
> > > >  	}
> > > >  }
> > > >  
> > > > -/**
> > > > - * i3c_master_bus_init() - initialize an I3C bus
> > > > - * @master: main master initializing the bus
> > > > - *
> > > > - * This function is following all initialisation steps described in the I3C
> > > > - * specification:
> > > > - *
> > > > - * 1. Attach I2C and statically defined I3C devs to the master so that the
> > > > - *    master can fill its internal device table appropriately
> > > > - *
> > > > - * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
> > > > - *    the master controller. That's usually where the bus mode is selected
> > > > - *    (pure bus or mixed fast/slow bus)
> > > > - *
> > > > - * 3. Instruct all devices on the bus to drop their dynamic address. This is
> > > > - *    particularly important when the bus was previously configured by someone
> > > > - *    else (for example the bootloader)
> > > > - *
> > > > - * 4. Disable all slave events.
> > > > - *
> > > > - * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
> > > > - *    devices that have a static address
> > > > - *
> > > > - * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
> > > > - *    remaining I3C devices
> > > > - *
> > > > - * Once this is done, all I3C and I2C devices should be usable.
> > > > - *
> > > > - * Return: a 0 in case of success, an negative error code otherwise.
> > > > - */
> > > > -static int i3c_master_bus_init(struct i3c_master_controller *master)
> > > > +static int i3c_master_attach_static_devs(struct i3c_master_controller *master)
> > > >  {
> > > >  	enum i3c_addr_slot_status status;
> > > >  	struct i2c_dev_boardinfo *i2cboardinfo;
> > > > @@ -1640,32 +1753,24 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
> > > >  	struct i2c_dev_desc *i2cdev;
> > > >  	int ret;
> > > >  
> > > > -	/*
> > > > -	 * First attach all devices with static definitions provided by the
> > > > -	 * FW.
> > > > -	 */
> > > >  	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
> > > >  		status = i3c_bus_get_addr_slot_status(&master->bus,
> > > >  						      i2cboardinfo->base.addr);
> > > > -		if (status != I3C_ADDR_SLOT_FREE) {
> > > > -			ret = -EBUSY;
> > > > -			goto err_detach_devs;
> > > > -		}
> > > > +		if (status != I3C_ADDR_SLOT_FREE)
> > > > +			return -EBUSY;
> > > >  
> > > >  		i3c_bus_set_addr_slot_status(&master->bus,
> > > >  					     i2cboardinfo->base.addr,
> > > >  					     I3C_ADDR_SLOT_I2C_DEV);
> > > >  
> > > >  		i2cdev = i3c_master_alloc_i2c_dev(master, i2cboardinfo);
> > > > -		if (IS_ERR(i2cdev)) {
> > > > -			ret = PTR_ERR(i2cdev);
> > > > -			goto err_detach_devs;
> > > > -		}
> > > > +		if (IS_ERR(i2cdev))
> > > > +			return PTR_ERR(i2cdev);
> > > >  
> > > >  		ret = i3c_master_attach_i2c_dev(master, i2cdev);
> > > >  		if (ret) {
> > > >  			i3c_master_free_i2c_dev(i2cdev);
> > > > -			goto err_detach_devs;
> > > > +			return ret;
> > > >  		}
> > > >  	}
> > > >  	list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) {
> > > > @@ -1676,27 +1781,68 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
> > > >  		if (i3cboardinfo->init_dyn_addr) {
> > > >  			status = i3c_bus_get_addr_slot_status(&master->bus,
> > > >  						i3cboardinfo->init_dyn_addr);
> > > > -			if (status != I3C_ADDR_SLOT_FREE) {
> > > > -				ret = -EBUSY;
> > > > -				goto err_detach_devs;
> > > > -			}
> > > > +			if (status != I3C_ADDR_SLOT_FREE)
> > > > +				return -EBUSY;
> > > >  		}
> > > >  
> > > >  		i3cdev = i3c_master_alloc_i3c_dev(master, &info);
> > > > -		if (IS_ERR(i3cdev)) {
> > > > -			ret = PTR_ERR(i3cdev);
> > > > -			goto err_detach_devs;
> > > > -		}
> > > > +		if (IS_ERR(i3cdev))
> > > > +			return PTR_ERR(i3cdev);
> > > >  
> > > >  		i3cdev->boardinfo = i3cboardinfo;
> > > >  
> > > >  		ret = i3c_master_attach_i3c_dev(master, i3cdev);
> > > >  		if (ret) {
> > > >  			i3c_master_free_i3c_dev(i3cdev);
> > > > -			goto err_detach_devs;
> > > > +			return ret;
> > > >  		}
> > > >  	}
> > > >  
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +/**
> > > > + * i3c_master_bus_init() - initialize an I3C bus
> > > > + * @master: main master initializing the bus
> > > > + *
> > > > + * This function is following all initialisation steps described in the I3C
> > > > + * specification:
> > > > + *
> > > > + * 1. Attach I2C and statically defined I3C devs to the master so that the
> > > > + *    master can fill its internal device table appropriately
> > > > + *
> > > > + * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
> > > > + *    the master controller. That's usually where the bus mode is selected
> > > > + *    (pure bus or mixed fast/slow bus)
> > > > + *
> > > > + * 3. Instruct all devices on the bus to drop their dynamic address. This is
> > > > + *    particularly important when the bus was previously configured by someone
> > > > + *    else (for example the bootloader)
> > > > + *
> > > > + * 4. Disable all slave events.
> > > > + *
> > > > + * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
> > > > + *    devices that have a static address
> > > > + *
> > > > + * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
> > > > + *    remaining I3C devices
> > > > + *
> > > > + * Once this is done, all I3C and I2C devices should be usable.
> > > > + *
> > > > + * Return: a 0 in case of success, an negative error code otherwise.
> > > > + */
> > > > +static int i3c_master_bus_init(struct i3c_master_controller *master)
> > > > +{
> > > > +	struct i3c_dev_desc *i3cdev;
> > > > +	int ret;
> > > > +
> > > > +	/*
> > > > +	 * First attach all devices with static definitions provided by the
> > > > +	 * FW.
> > > > +	 */
> > > > +	ret = i3c_master_attach_static_devs(master);
> > > > +	if (ret)
> > > > +		goto err_detach_devs;
> > > >  	/*
> > > >  	 * Now execute the controller specific ->bus_init() routine, which
> > > >  	 * might configure its internal logic to match the bus limitations.
> > > > @@ -1780,45 +1926,76 @@ i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev)
> > > >  }
> > > >  
> > > >  /**
> > > > - * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> > > > - * @master: master used to send frames on the bus
> > > > - * @addr: I3C slave dynamic address assigned to the device
> > > > + * i3c_master_add_i2c_dev_locked() - add an I2C slave to the bus
> > > > + * @master: master used to register I2C device
> > > > + * @addr: I2C device address
> > > > + * @lvr: legacy virtual register value
> > > >   *
> > > > - * This function is instantiating an I3C device object and adding it to the
> > > > - * I3C device list. All device information are automatically retrieved using
> > > > - * standard CCC commands.
> > > > - *
> > > > - * The I3C device object is returned in case the master wants to attach
> > > > - * private data to it using i3c_dev_set_master_data().
> > > > + * This function is instantiating an I2C device object and adding it to the
> > > > + * I2C device list.
> > > >   *
> > > >   * This function must be called with the bus lock held in write mode.
> > > >   *
> > > >   * Return: a 0 in case of success, an negative error code otherwise.
> > > >   */
> > > > -int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > > -				  u8 addr)
> > > > +int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
> > > > +				  u16 addr, u8 lvr)
> > > >  {
> > > > -	struct i3c_device_info info = { .dyn_addr = addr };
> > > > -	struct i3c_dev_desc *newdev, *olddev;
> > > > -	u8 old_dyn_addr = addr, expected_dyn_addr;
> > > > -	struct i3c_ibi_setup ibireq = { };
> > > > -	bool enable_ibi = false;
> > > > +	enum i3c_addr_slot_status status;
> > > > +	struct i2c_dev_desc *i2cdev;
> > > >  	int ret;
> > > >  
> > > >  	if (!master)
> > > >  		return -EINVAL;
> > > >  
> > > > -	newdev = i3c_master_alloc_i3c_dev(master, &info);
> > > > -	if (IS_ERR(newdev))
> > > > -		return PTR_ERR(newdev);
> > > > +	status = i3c_bus_get_addr_slot_status(&master->bus,
> > > > +					      addr);
> > > > +	if (status != I3C_ADDR_SLOT_FREE)
> > > > +		return -EBUSY;
> > > >  
> > > > -	ret = i3c_master_attach_i3c_dev(master, newdev);
> > > > -	if (ret)
> > > > +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> > > > +				     I3C_ADDR_SLOT_I2C_DEV);
> > > > +
> > > > +	i2cdev = i3c_master_alloc_i2c_dev_no_boardinfo(master, addr, lvr);
> > > > +
> > > > +	if (IS_ERR(i2cdev)) {
> > > > +		ret = PTR_ERR(i2cdev);
> > > > +		goto err_free_dev;
> > > > +	}
> > > > +
> > > > +	i2cdev->boardinfo = i3c_master_find_i2c_boardinfo(master, addr, lvr);
> > > > +
> > > > +	ret = i3c_master_attach_i2c_dev(master, i2cdev);
> > > > +
> > > > +	if (ret) {
> > > > +		ret = PTR_ERR(i2cdev);
> > > >  		goto err_free_dev;
> > > > +	}
> > > > +
> > > > +	return 0;
> > > > +
> > > > +err_free_dev:
> > > > +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> > > > +				     I3C_ADDR_SLOT_FREE);
> > > > +	i3c_master_free_i2c_dev(i2cdev);
> > > > +
> > > > +	return ret;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(i3c_master_add_i2c_dev_locked);
> > > > +
> > > > +static int
> > > > +i3c_master_retrieve_info_and_reuse(struct i3c_master_controller *master,
> > > > +				   struct i3c_dev_desc *newdev)
> > > > +{
> > > > +	struct i3c_dev_desc *olddev;
> > > > +	u8 old_dyn_addr = newdev->info.dyn_addr, expected_dyn_addr;
> > > > +	struct i3c_ibi_setup ibireq = { };
> > > > +	bool enable_ibi = false;
> > > > +	int ret;
> > > >  
> > > >  	ret = i3c_master_retrieve_dev_info(newdev);
> > > >  	if (ret)
> > > > -		goto err_detach_dev;
> > > > +		return ret;
> > > >  
> > > >  	olddev = i3c_master_search_i3c_dev_duplicate(newdev);
> > > >  	if (olddev) {
> > > > @@ -1857,7 +2034,7 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > >  
> > > >  	ret = i3c_master_reattach_i3c_dev(newdev, old_dyn_addr);
> > > >  	if (ret)
> > > > -		goto err_detach_dev;
> > > > +		return ret;
> > > >  
> > > >  	/*
> > > >  	 * Depending on our previous state, the expected dynamic address might
> > > > @@ -1920,6 +2097,50 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > >  	}
> > > >  
> > > >  	return 0;
> > > > +}
> > > > +
> > > > +/**
> > > > + * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> > > > + * @master: master used to send frames on the bus
> > > > + * @addr: I3C slave dynamic address assigned to the device
> > > > + *
> > > > + * This function is instantiating an I3C device object and adding it to the
> > > > + * I3C device list. All device information are automatically retrieved using
> > > > + * standard CCC commands.
> > > > + *
> > > > + * The I3C device object is returned in case the master wants to attach
> > > > + * private data to it using i3c_dev_set_master_data().
> > > > + *
> > > > + * This function must be called with the bus lock held in write mode.
> > > > + *
> > > > + * Return: a 0 in case of success, an negative error code otherwise.
> > > > + */
> > > > +int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > > +				  u8 addr)
> > > > +{
> > > > +	struct i3c_device_info info = { .dyn_addr = addr };
> > > > +	struct i3c_dev_desc *newdev;
> > > > +	int ret;
> > > > +
> > > > +	if (!master)
> > > > +		return -EINVAL;
> > > > +
> > > > +	newdev = i3c_master_alloc_i3c_dev(master, &info);
> > > > +	if (IS_ERR(newdev))
> > > > +		return PTR_ERR(newdev);
> > > > +
> > > > +	ret = i3c_master_attach_i3c_dev(master, newdev);
> > > > +	if (ret)
> > > > +		goto err_free_dev;
> > > > +
> > > > +	if (i3c_master_owns_bus(master)) {
> > > > +		ret = i3c_master_retrieve_info_and_reuse(master, newdev);
> > > > +		if (ret)
> > > > +			goto err_detach_dev;
> > > > +	} else
> > > > +		master->want_to_acquire_bus = true;
> > > > +
> > > > +	return 0;
> > > >  
> > > >  err_detach_dev:
> > > >  	if (newdev->dev && newdev->dev->desc)
> > > > @@ -2101,11 +2322,15 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
> > > >  	}
> > > >  
> > > >  	i3c_bus_normaluse_lock(&master->bus);
> > > > +	ret = i3c_master_acquire_bus_ownership(master);
> > > > +	if (ret)
> > > > +		goto err_unlock_bus;
> > > >  	dev = i3c_master_find_i2c_dev_by_addr(master, addr);
> > > >  	if (!dev)
> > > >  		ret = -ENOENT;
> > > >  	else
> > > >  		ret = master->ops->i2c_xfers(dev, xfers, nxfers);
> > > > +err_unlock_bus:
> > > >  	i3c_bus_normaluse_unlock(&master->bus);
> > > >  
> > > >  	return ret ? ret : nxfers;
> > > > @@ -2144,9 +2369,12 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
> > > >  	 * We silently ignore failures here. The bus should keep working
> > > >  	 * correctly even if one or more i2c devices are not registered.
> > > >  	 */
> > > > -	i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
> > > > +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> > > > +		if (!i2cdev->boardinfo)
> > > > +			continue;
> > > >  		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
> > > >  
> > > > +	}
> > > >  	return 0;
> > > >  }
> > > >  
> > > > @@ -2385,9 +2613,76 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
> > > >  	     !ops->recycle_ibi_slot))
> > > >  		return -EINVAL;
> > > >  
> > > > +	/*
> > > > +	 * If mastership request is supported, we also need hooks to control
> > > > +	 * when mastership request can occur by enabling/disabling the event.
> > > > +	 */
> > > > +	if (ops->request_mastership &&
> > > > +	    (!ops->enable_mr_events || !ops->disable_mr_events))
> > > > +		return -EINVAL;
> > > >  	return 0;
> > > >  }
> > > >  
> > > > +static void i3c_master_register_new_devs(struct i3c_master_controller *master)
> > > > +{
> > > > +	/*
> > > > +	 * We can register devices received from master by DEFSLVS.
> > > > +	 */
> > > > +	i3c_bus_normaluse_lock(&master->bus);
> > > > +	i3c_master_register_new_i3c_devs(master);
> > > > +	i3c_master_register_new_i2c_devs(master);
> > > > +	i3c_bus_normaluse_unlock(&master->bus);
> > > > +}
> > > > +
> > > > +/**
> > > > + * i3c_master_bus_takeover() - register new I3C devices on bus takeover
> > > > + * @master: master used to send frames on the bus
> > > > + *
> > > > + * This function is useful when devices were not added
> > > > + * during initialization or when new device joined the bus
> > > > + * which wasn't under our control.
> > > > + */
> > > > +void i3c_master_bus_takeover(struct i3c_master_controller *master)
> > > > +{
> > > > +	struct i3c_dev_desc *i3cdev, *i3ctmp;
> > > > +	int ret;
> > > > +
> > > > +	master->want_to_acquire_bus = false;
> > > 
> > > Can you explain the usage of this variable?
> > > 
> > 
> > The idea of this was to let HC know that we want to acquire the bus after
> > ENEC(MR) received in slave mode.
> 
> With the logic that I proposed you don't need this. When received ENEC 
> you will try to get the bus ownership if HC not fully initialized or have 
> DEFSLVS to add, otherwise you don't need to get the bus ownership.

In case devices on the bus are the same, I agree. But please consider the case
when slave joins the bus (Hot-Join) and MR event is disabled for now, our
secondary master receives DEFSLVS, we add that device to the subsystem but
cannot request mastership yet. We need a flag to indicate that we should
request mastership on next ENEC(MR). It doesn't make sense to request
mastership every time when ENEC(MR) is received.

> 
> > 
> > > > +
> > > > +	if (!master->init_done)
> > > > +		return;
> > > > +
> > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > +	master->ops->populate_bus(master);
> > > > +
> > > > +	list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c,
> > > > +				 common.node) {
> > > > +		if (i3cdev->info.pid)
> > > > +			continue;
> > > > +
> > > > +		ret = i3c_master_retrieve_info_and_reuse(master, i3cdev);
> > > > +		if (ret) {
> > > > +			if (i3cdev->dev && i3cdev->dev->desc)
> > > > +				i3cdev->dev->desc = NULL;
> > > > +
> > > > +			i3c_master_detach_i3c_dev(i3cdev);
> > > > +		}
> > > > +	}
> > > > +
> > > > +	/*
> > > > +	 * If current master finished bus initialization properly, we can
> > > > +	 * enable Mastership event.
> > > > +	 */
> > > > +	ret = i3c_master_enable_mr_events_locked(master);
> > > > +	if (ret)
> > > > +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> > > > +
> > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > > +
> > > > +	i3c_master_register_new_devs(master);
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(i3c_master_bus_takeover);
> > > > +
> > > >  /**
> > > >   * i3c_master_init() - initializes all the structures required by I3C master
> > > >   * @master: master used to send frames on the bus
> > > > @@ -2417,9 +2712,6 @@ int i3c_master_init(struct i3c_master_controller *master,
> > > >  	struct i2c_dev_boardinfo *i2cbi;
> > > >  	int ret;
> > > >  
> > > > -	/* We do not support secondary masters yet. */
> > > > -	if (secondary)
> > > > -		return -ENOTSUPP;
> > > >  
> > > >  	ret = i3c_master_check_ops(ops);
> > > >  	if (ret)
> > > > @@ -2432,6 +2724,7 @@ int i3c_master_init(struct i3c_master_controller *master,
> > > >  	master->dev.release = i3c_masterdev_release;
> > > >  	master->ops = ops;
> > > >  	master->secondary = secondary;
> > > > +	master->want_to_acquire_bus = secondary;
> > > >  	INIT_LIST_HEAD(&master->boardinfo.i2c);
> > > >  	INIT_LIST_HEAD(&master->boardinfo.i3c);
> > > >  
> > > > @@ -2488,6 +2781,92 @@ void i3c_master_cleanup(struct i3c_master_controller *master)
> > > >  EXPORT_SYMBOL_GPL(i3c_master_cleanup);
> > > >  
> > > >  /**
> > > > + * i3c_secondary_master_register() - register an secondary I3C master
> > > > + * @master: master used to send frames on the bus
> > > > + * @info: master info, describes this device
> > > > + *
> > > > + * This function takes care of everything for you:
> > > > + *
> > > > + * - updates this master info
> > > > + * - registers the I2C adapter
> > > > + * - if possible, populates the bus with devices received by DEFSLVS
> > > > + *   command
> > > > + *
> > > > + * Return: 0 in case of success, a negative error code otherwise.
> > > > + */
> > > > +int i3c_secondary_master_register(struct i3c_master_controller *master,
> > > > +				  struct i3c_device_info *info)
> > > > +{
> > > > +	int ret;
> > > > +
> > > > +	ret = i3c_master_set_info(master, info, master->secondary);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > > +	ret = master->ops->bus_init(master);
> > > > +	if (ret)
> > > > +		return ret;
> > > 
> > > At this point you don't have enough information to do the bus 
> > > initialization.
> > > 
> > 
> > Actually, current ->bus_init() implementations (in CDNS and DW) does not
> > initialize the bus. We are just setting the mode, configuring some init values
> > in the registers and enabling the core. Maybe we should rename it?
> 
> The name for me its ok. My point was that when you call 
> i3c_secondary_master_register() in CDNS you don't have yet DEFSLVS 
> information.

It depends. When current master did not initialize the bus yet, this is true.
But when master and the bus are already initialized, I have DEFSLVS. Different
story is that devices aren't added to the subsystem yet. So what I have do in
that case is to enable to let HC operate and populate the bus later (using
->populate_bus() hook)

> 
> > 
> > > > +
> > > > +	ret = device_add(&master->dev);
> > > > +	if (ret)
> > > > +		return -1;
> > > > +
> > > > +	/*
> > > > +	 * Expose our I3C bus as an I2C adapter so that I2C devices are exposed
> > > > +	 * through the I2C subsystem.
> > > > +	 */
> > > > +	ret = i3c_master_i2c_adapter_init(master);
> > > > +	if (ret)
> > > > +		goto err_del_dev;
> > > > +
> > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > +	/*
> > > > +	 * If possible, request mastership and try to populate the bus.
> > > > +	 */
> > > > +	ret = i3c_master_request_mastership_locked(master);
> > > > +	if (ret)
> > > > +		dev_warn(&master->dev,
> > > > +			 "Mastership failed at init time (ret = %i)", ret);
> > > > +
> > > > +	/*
> > > > +	 * No matter if mastership takeover passed or not, add partialy
> > > > +	 * discovered devices. We can register them when ENEC(MR) is enabled.
> > > > +	 */
> > > > +	master->ops->populate_bus(master);
> > > > +
> > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > > +
> > > > +	/*
> > > > +	 * We're done initializing the bus and the controller, we can now
> > > > +	 * register I3C devices obtained by DEFSLVS.
> > > > +	 */
> > > > +	master->init_done = true;
> > > > +	i3c_master_register_new_devs(master);
> > > > +
> > > > +	/*
> > > > +	 * If we are owning the bus, enable ENEC(MR) to let other masters
> > > > +	 * initialize their bus.
> > > > +	 */
> > > > +	if (i3c_master_owns_bus(master)) {
> > > > +		i3c_bus_maintenance_lock(&master->bus);
> > > > +		ret = i3c_master_enable_mr_events_locked(master);
> > > > +		i3c_bus_maintenance_unlock(&master->bus);
> > > > +		if (ret)
> > > > +			dev_warn(&master->dev,
> > > > +				 "ENEC(MR) failed (ret = %i)", ret);
> > > > +	}
> > > > +
> > > > +
> > > > +	return 0;
> > > > +
> > > > +err_del_dev:
> > > > +	device_del(&master->dev);
> > > > +
> > > > +	return ret;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(i3c_secondary_master_register);
> > > > +
> > > > +/**
> > > >   * i3c_master_register() - register an primary I3C master
> > > >   * @master: master used to send frames on the bus
> > > >   * @info: master info, describes this device
> > > > @@ -2509,7 +2888,6 @@ int i3c_master_register(struct i3c_master_controller *master,
> > > >  	ret = i3c_master_set_info(master, info, master->secondary);
> > > >  	if (ret)
> > > >  		return ret;
> > > > -
> > > >  	ret = i3c_master_bus_init(master);
> > > >  	if (ret)
> > > >  		return ret;
> > > > @@ -2535,6 +2913,16 @@ int i3c_master_register(struct i3c_master_controller *master,
> > > >  	i3c_master_register_new_i3c_devs(master);
> > > >  	i3c_bus_normaluse_unlock(&master->bus);
> > > >  
> > > > +	/*
> > > > +	 * Enable ENEC(MR) and let other masters request mastership
> > > > +	 * and initialize their bus.
> > > > +	 */
> > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > +	ret = i3c_master_enable_mr_events_locked(master);
> > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > > +	if (ret)
> > > > +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> > > > +
> > > >  	return 0;
> > > >  
> > > >  err_del_dev:
> > > > @@ -2548,6 +2936,29 @@ int i3c_master_register(struct i3c_master_controller *master,
> > > >  EXPORT_SYMBOL_GPL(i3c_master_register);
> > > >  
> > > >  /**
> > > > + * i3c_master_mastership_ack() - acknowledges bus takeover.
> > > > + * @master: master used to send frames on the bus
> > > > + * @addr: I3C device address
> > > > + *
> > > > + * This function acknowledges bus takeover.
> > > > + *
> > > > + * Return: 0 in case of success, a negative error code otherwise.
> > > > + */
> > > > +int i3c_master_mastership_ack(struct i3c_master_controller *master,
> > > > +			      u8 addr)
> > > > +{
> > > > +	int ret;
> > > > +
> > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > +	ret = i3c_master_get_accmst_locked(master, addr);
> > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > > +
> > > > +	return ret;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(i3c_master_mastership_ack);
> > > > +
> > > > +
> > > > +/**
> > > >   * i3c_master_unregister() - unregister an I3C master
> > > >   * @master: master used to send frames on the bus
> > > >   *
> > > > @@ -2557,6 +2968,9 @@ EXPORT_SYMBOL_GPL(i3c_master_register);
> > > >   */
> > > >  int i3c_master_unregister(struct i3c_master_controller *master)
> > > >  {
> > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > +	i3c_master_disable_mr_events(master);
> > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > >  	i3c_master_i2c_adapter_cleanup(master);
> > > >  	i3c_master_unregister_i3c_devs(master);
> > > >  	i3c_master_bus_cleanup(master);
> > > > diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
> > > > index e089771..6ac9b46 100644
> > > > --- a/include/linux/i3c/master.h
> > > > +++ b/include/linux/i3c/master.h
> > > > @@ -421,6 +421,26 @@ struct i3c_bus {
> > > >   *		      for a future IBI
> > > >   *		      This method is mandatory only if ->request_ibi is not
> > > >   *		      NULL.
> > > > + * @request_mastership: requests bus mastership. Mastership is requested
> > > > + *                      automatically when device driver wants to transfer
> > > > + *                      data using a master that does not currently
> > > > + *                      owns the bus.
> > > > + * @enable_mr_events: enable the Mastership event. Master driver can prepare
> > > > + *                    its internal state to be ready for incoming mastership
> > > > + *                    requests and then should send ENEC(MR) command to let
> > > > + *                    other masters take control over the bus.
> > > > + * @disable_mr_events: disable the Mastership event. Master driver should
> > > > + *                     immediately send DISEC(MR) command and can perform other
> > > > + *                     operations. For example, recycle IBI slot if used before
> > > > + *                     for MR event.
> > > > + * @populate_pus: populates the bus. Called after bus takeover. Secondary
> > > > + *                master can't perform DAA procedure. This function allows to
> > > > + *                update devices received from previous bus owner in DEFSLVS
> > > > + *                command. Useful also when new device joins the bus controlled
> > > > + *                by secondary master, main master will be able to add
> > > > + *                this device after mastership takeover. Driver should also
> > > > + *		  update bus mode when I2C device is on the bus.
> > > > + *
> > > >   */
> > > >  struct i3c_master_controller_ops {
> > > >  	int (*bus_init)(struct i3c_master_controller *master);
> > > > @@ -447,6 +467,10 @@ struct i3c_master_controller_ops {
> > > >  	int (*disable_ibi)(struct i3c_dev_desc *dev);
> > > >  	void (*recycle_ibi_slot)(struct i3c_dev_desc *dev,
> > > >  				 struct i3c_ibi_slot *slot);
> > > > +	int (*request_mastership)(struct i3c_master_controller *master);
> > > > +	int (*enable_mr_events)(struct i3c_master_controller *master);
> > > > +	int (*disable_mr_events)(struct i3c_master_controller *master);
> > > > +	int (*populate_bus)(struct i3c_master_controller *master);
> > > >  };
> > > >  
> > > >  /**
> > > > @@ -488,6 +512,7 @@ struct i3c_master_controller {
> > > >  	} boardinfo;
> > > >  	struct i3c_bus bus;
> > > >  	struct workqueue_struct *wq;
> > > > +	bool want_to_acquire_bus;
> > > >  };
> > > >  
> > > >  /**
> > > > @@ -526,6 +551,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master);
> > > >  int i3c_master_get_free_addr(struct i3c_master_controller *master,
> > > >  			     u8 start_addr);
> > > >  
> > > > +int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
> > > > +				  u16 addr, u8 lvr);
> > > >  int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > >  				  u8 addr);
> > > >  int i3c_master_do_daa(struct i3c_master_controller *master);
> > > > @@ -535,9 +562,14 @@ int i3c_master_init(struct i3c_master_controller *master,
> > > >  		    const struct i3c_master_controller_ops *ops,
> > > >  		    bool secondary);
> > > >  void i3c_master_cleanup(struct i3c_master_controller *master);
> > > > +int i3c_secondary_master_register(struct i3c_master_controller *master,
> > > > +				  struct i3c_device_info *info);
> > > >  int i3c_master_register(struct i3c_master_controller *master,
> > > >  			struct i3c_device_info *info);
> > > >  int i3c_master_unregister(struct i3c_master_controller *master);
> > > > +int i3c_master_mastership_ack(struct i3c_master_controller *master,
> > > > +			      u8 addr);
> > > > +void i3c_master_bus_takeover(struct i3c_master_controller *master);
> > > >  int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode);
> > > >  
> > > >  /**
> > > > @@ -648,7 +680,5 @@ void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot);
> > > >  
> > > >  struct i3c_ibi_slot *i3c_master_get_free_ibi_slot(struct i3c_dev_desc *dev);
> > > >  
> > > > -void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> > > > -void i3c_bus_maintenance_unlock(struct i3c_bus *bus);
> > > >  
> > > >  #endif /* I3C_MASTER_H */
> > > > -- 
> > > > 2.4.5
> > > 
> > > In generally I found this intrusive for the current eco system.
> > > 
> > > I propose the following:
> > > 1 - Keep the function i3c_master_register() as is and go out before 
> > 
> > We had that version previously. We decided to split it.
> 
> You just need to split the secondary master part from it. So you can go 
> out before i3c_master_bus_init() and keep the same function.

We discussed that with Boris and we decided to split this function in this
version to make things clear.

> 
> Them use i3c_secondary_master_register() when received DEFSLVS or ENEC 
> MR.

It is also possible that our controller received DA and DEFSLVS even before
master registration. We should try to register that, this is something I'm
testing in my scenarios.

> 
> > 
> > > i3c_master_bus_init() if secondary master.
> > > @Boris Brezillon is it possible to replace device_initialize() device_add() with device_register()?
> > > 
> > > 2 - When received DEFSLVS commands add devices to a link list like 
> > > boardinfo.
> > 
> > If DEFSLVS received devices are partialy added at init time.
> > 
> > >   Get bus ownership if there is DEFSLVS to add or secondary master not 
> > > initialized. 
> > > 
> > > 3 - When received ENEC MR
> > 
> > I thought it works like that :-) When ENEC(MR) received, HC driver adds devices
> > from DEFSLVS frame,
> 
> Yes, but in your case the logic is in HC. Let the subsystem do that task 
> when you switch the role.
> I think you did that in v1 or v2.

True, but we also decided to do this in HC. We didn't want to standarize events
yet.

> 
> > 
> > >   Get bus ownership if there is DEFSLVS to add or secondary master not 
> > > initialized.
> > > 
> > > 4 - When secondary master became current master.
> > 
> > and calls i3c_master_bus_takeover() to let subsystem gather device information
> > and register them.
> 
> It  is not clear to me if it is already the current master.

Bus takeover should be performed right after we got the control over the bus. I
don't know how to make is simpler.

> 
> > 
> > >   Attach new devices to the host controller and retrieve device info 
> > > (same logic as in i3c_master_add_i3c_dev_locked).
> > > 
> > > With this approach on HC side you just need to add the secondary master 
> > > stuff without changing the current code and leave for the subsystem the 
> > > responsible to manage all these secondary master task.
> > 
> > This may be difficult for some controllers, depends where DEFSLVS device
> > information is stored.
> 
> That is the main reason I want pass DEFSLVS to a list in the subsystem.
> I think it will be common to everyone receive a notification that DEFSLVS 
> arrived.

As I said before, I'm not sure if this is good idea or not. We are registering
the devices in HC drivers after DAA using i3c_master_add_i3c_dev_locked() and
this isn't the issue. I wonder why it could be the problem here. The
difference here is only the source of the devices, not DAA but DEFSLVS.

> 
> > I also cannot find information about that part in
> > MIPI I3C HCI specification. This part can be vendor specific. What do you
> > think?
> 
> It is not defined int v1.0

I see now that HCI spec does not cover secondary master functionality at all.

> 
> > 
> > > 
> > > Let me know if this works for you.
> > > 
> > > 
> > > Best regards,
> > > Vitor Soares
> > 
> > -- 
> > -- 
> > Przemyslaw Gaj
> 
> Best regards,
> Vitor Soares
> 
> 

-- 
-- 
Przemyslaw Gaj

_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem
  2019-07-12 10:10         ` Przemyslaw Gaj
@ 2019-07-12 11:28           ` Vitor Soares
  2019-08-11 10:17             ` Boris Brezillon
  0 siblings, 1 reply; 21+ messages in thread
From: Vitor Soares @ 2019-07-12 11:28 UTC (permalink / raw)
  To: Przemyslaw Gaj, Vitor Soares; +Cc: linux-i3c, agolec, rafalc, bbrezillon

From: Przemyslaw Gaj <pgaj@cadence.com>
Date: Fri, Jul 12, 2019 at 11:10:43

> Hi Vitor,
> 
> The 07/11/2019 10:11, Vitor Soares wrote:
> > EXTERNAL MAIL
> > 
> > 
> > From: Przemyslaw Gaj <pgaj@cadence.com>
> > Date: Thu, Jul 11, 2019 at 06:28:18
> > 
> > > Hi Vitor,
> > > 
> > > The 07/10/2019 18:04, Vitor Soares wrote:
> > > > EXTERNAL MAIL
> > > > 
> > > > 
> > > > From: Przemyslaw Gaj <pgaj@cadence.com>
> > > > Date: Sat, Jun 22, 2019 at 21:55:02
> > > > 
> > > > > This patch adds support for mastership request to I3C subsystem.
> > > > > 
> > > > > Mastership event is enabled globally.
> > > > > 
> > > > > Mastership is requested automatically when device driver
> > > > > tries to transfer data using master controller in slave mode.
> > > > > 
> > > > > There is still some limitation:
> > > > > - I2C devices are registered on secondary master side if boardinfo
> > > > > entry matching the info transmitted through the DEFSLVS frame.
> > > > > 
> > > > > Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
> > > > > 
> > > > > ---
> > > > > 
> > > > > Main changes between v4 and v5:
> > > > > - Add function to test if master owns the bus
> > > > > - Add i3c_secondary_master_register() function
> > > > > - Add populate_bus() hook to populate the bus after mastership takeover
> > > > 
> > > > For me this task is for the sub-system not the host controller.
> > > > 
> > > 
> > > I'm not sure where device information is stored in DW controller but in CDNS
> > > controller DEFSLVS frame is processed in the device and the only thing I got is
> > > information that DEFSLVS came in. 
> > 
> > When you receive this notification you can add the device to subsystem to 
> > be initialized later when get bus ownership.
> 
> I added this hook mostly because we have to lock the bus during devices
> addition. If we pass DEFSLVS devices information to the system in some
> structure, we should be ok. We can lock the bus in the framework and register
> all the devices. But I still don't feel this is good solution, I'll have to
> do the job once again which HW did before

Your HW just fill a table with the DEFSLVS data and you still have to 
access, retrieve the information and attached to the controller (same 
approach as DAA).

If all these management is passed to the subsystem it will be more easy 
to maintain and HC agonistic.

> 
> @Boris, what do you think about that?
> 
> > 
> > > I need to inform subsystem that there are new
> > > device (if any).
> > > I remember we talkad about that already, you have access to
> > > DEFSLVS information directly, correct?
> > 
> > I can process it in the HC driver, but my point is that I want to rely it 
> > to the subsystem the bus population with the function already present.
> > 
> 
> So, do you want to pack those informations back to i3c_ccc_defslvs and pass to
> the subsystem?

Not necessary. It can be passed addr, bcr, dcr and lvr. 

In the subsystem I think it should be a list of i3c_ccc_defslvs that 
holds DEFSLVS information.

> 
> > > 
> > > > > - Rework device information retrieval to allow adding partialy discovered
> > > > > devices
> > > > > 
> > > > > Main changes between v3 and v4:
> > > > > - Add i3c_master_acquire_bus_ownership to acquire the bus
> > > > > - Refactored the code
> > > > > 
> > > > > Main changes between v2 and v3:
> > > > > - Add i3c_bus_downgrade_maintenance_lock() for downgrading the bus
> > > > > lock from maintenance to normal use
> > > > > - Add additional fields to i2c_dev_desc for DEFSLVS purpose (addr, lvr)
> > > > > - Add i3c_master_register_new_i2c_devs() function to register I2C devices
> > > > > - Reworked I2C devices registration on secondary master side
> > > > > 
> > > > > Changes in v2:
> > > > > - Add mastership disable event hook
> > > > > - Changed name of mastership enable event hook
> > > > > - Add function to test if master owns the bus
> > > > > - Removed op_mode
> > > > > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > > > > pass full i3c_device_info
> > > > > - Changed name of mastership enable event hook
> > > > > - Add function to test if master owns the bus
> > > > > - Removed op_mode
> > > > > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > > > > pass full i3c_device_info
> > > > > - Removed redundant DEFSLVS command before GETACCMST
> > > > > - Add i3c_master_bus_takeover function. There is a need to lock
> > > > > the bus before adding devices and no matter of the controller
> > > > > devices have to be added after mastership takeover.
> > > > > - Add device registration during initialization on secondary master
> > > > > side. Devices received by DEFSLVS (if occured). If not, device
> > > > > initialization is deffered untill next mastership request.
> > > > > ---
> > > > >  drivers/i3c/device.c       |  26 ++
> > > > >  drivers/i3c/internals.h    |   4 +
> > > > >  drivers/i3c/master.c       | 588 ++++++++++++++++++++++++++++++++++++++-------
> > > > >  include/linux/i3c/master.h |  34 ++-
> > > > >  4 files changed, 563 insertions(+), 89 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
> > > > > index 69cc040..b60f637 100644
> > > > > --- a/drivers/i3c/device.c
> > > > > +++ b/drivers/i3c/device.c
> > > > > @@ -43,7 +43,13 @@ int i3c_device_do_priv_xfers(struct i3c_device *dev,
> > > > >  	}
> > > > >  
> > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > +	if (ret)
> > > > > +		goto err_unlock_bus;
> > > > > +
> > > > >  	ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
> > > > > +
> > > > > +err_unlock_bus:
> > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > >  
> > > > >  	return ret;
> > > > > @@ -114,11 +120,17 @@ int i3c_device_enable_ibi(struct i3c_device *dev)
> > > > >  	int ret = -ENOENT;
> > > > >  
> > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > +	if (ret)
> > > > > +		goto err_unlock_bus;
> > > > > +
> > > > >  	if (dev->desc) {
> > > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > > >  		ret = i3c_dev_enable_ibi_locked(dev->desc);
> > > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > > >  	}
> > > > > +
> > > > > +err_unlock_bus:
> > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > >  
> > > > >  	return ret;
> > > > > @@ -145,11 +157,17 @@ int i3c_device_request_ibi(struct i3c_device *dev,
> > > > >  		return -EINVAL;
> > > > >  
> > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > +	if (ret)
> > > > > +		goto err_unlock_bus;
> > > > > +
> > > > >  	if (dev->desc) {
> > > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > > >  		ret = i3c_dev_request_ibi_locked(dev->desc, req);
> > > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > > >  	}
> > > > > +
> > > > > +err_unlock_bus:
> > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > >  
> > > > >  	return ret;
> > > > > @@ -166,12 +184,20 @@ EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
> > > > >   */
> > > > >  void i3c_device_free_ibi(struct i3c_device *dev)
> > > > >  {
> > > > > +	int ret;
> > > > > +
> > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > +	if (ret)
> > > > > +		goto err_unlock_bus;
> > > > > +
> > > > >  	if (dev->desc) {
> > > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > > >  		i3c_dev_free_ibi_locked(dev->desc);
> > > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > > >  	}
> > > > > +
> > > > > +err_unlock_bus:
> > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > >  }
> > > > >  EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
> > > > > diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
> > > > > index 86b7b44..cdfc5bf 100644
> > > > > --- a/drivers/i3c/internals.h
> > > > > +++ b/drivers/i3c/internals.h
> > > > > @@ -14,6 +14,10 @@ extern struct bus_type i3c_bus_type;
> > > > >  
> > > > >  void i3c_bus_normaluse_lock(struct i3c_bus *bus);
> > > > >  void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
> > > > > +void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> > > > > +void i3c_bus_maintenance_unlock(struct i3c_bus *bus);
> > > > 
> > > > These function are static.
> > > > 
> > > 
> > > I forgot to revert that change to previous state.
> > > 
> > > > > +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master);
> > > > > +
> > > > 
> > > > What do you think to pass this logic to master.c?
> > > > 
> > > 
> > > Isn't it there?
> > 
> > I meant make it static and remove its call from device.c.
> > 
> > > 
> > > > >  
> > > > >  int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
> > > > >  				 struct i3c_priv_xfer *xfers,
> > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> > > > > index cbace14..3b44e66 100644
> > > > > --- a/drivers/i3c/master.c
> > > > > +++ b/drivers/i3c/master.c
> > > > > @@ -93,6 +93,18 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
> > > > >  	up_read(&bus->lock);
> > > > >  }
> > > > >  
> > > > > +/*
> > > > > + * i3c_bus_downgrade_maintenance_lock - Downgrade the bus lock to normal
> > > > > + * operation
> > > > > + *
> > > > > + * Should be called when a maintenance operation is done and normal
> > > > > + * operation is planned. See i3c_bus_maintenance_lock() and
> > > > > + * i3c_bus_normaluse_lock() for more details.
> > > > > + */
> > > > > +static void i3c_bus_downgrade_maintenance_lock(struct i3c_bus *bus)
> > > > > +{
> > > > > +	downgrade_write(&bus->lock);
> > > > > +}
> > > > >  static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
> > > > >  {
> > > > >  	return container_of(dev, struct i3c_master_controller, dev);
> > > > > @@ -341,6 +353,22 @@ static int i3c_device_probe(struct device *dev)
> > > > >  	return driver->probe(i3cdev);
> > > > >  }
> > > > >  
> > > > > +static int
> > > > > +i3c_master_enable_mr_events_locked(struct i3c_master_controller *master)
> > > > > +{
> > > > > +	if (!master->ops->enable_mr_events)
> > > > > +		return -ENOTSUPP;
> > > > > +
> > > > > +	return master->ops->enable_mr_events(master);
> > > > > +}
> > > > > +
> > > > > +static void i3c_master_disable_mr_events(struct i3c_master_controller *master)
> > > > > +{
> > > > > +	if (!master->ops->disable_mr_events)
> > > > > +		return;
> > > > > +
> > > > > +	master->ops->disable_mr_events(master);
> > > > > +}
> > > > 
> > > > Add new line.
> > > > 
> > > > It is not clear to me what you expect with these functions. Do you want 
> > > > to enable MR from all devices? Just some of them? How do you decide which 
> > > > secondary masters are allow earn the bus ownership?
> > > > 
> > > 
> > > We discussed this also. For now, we enable ENEC for all masters on the bus, we
> > > can change it later if needed. 
> > 
> > I would say to expand the current ibi framework to accommodate MR and
> 
> Can you tell something more here? What benefits you see

Just starting with the name. IBI stands for In Band Interrupt which can 
be MR, HJ or SIR.

Also the concept is the same, let say you are registering a SIR w/out 
data but in fact it is a MR. 

> 
> > also add platform entry to allow secondary masters on the bus.
> 
> This is something we can consider, to select devices which can request
> mastership. But I don't see the problem adding that later also.



> 
> > 
> > > Also, priority level is encoded in slave address
> > > so current master will give the control to the master with lower address first.
> > > It shouldn't be a problem.
> > 
> > You can have security issues and the devices on the bus might not be 
> > prepared to work in multi-master environment.
> 
> I don't get it, can you explan what do you mean? Which devices might not be
> prapared to work in multi-master environment, slaves? Key feature of I3C is
> multi-master capability. Mastership request should also be transparent for pure
> slaves on the bus. Of course, secondary masters should work in multi-master
> configuration

So you are probing the same hw device on two different systems. This mean 
that in system A you can have the configuration A and in system B the 
configuration B.
How will you deal with this?

> 
> > 
> > > 
> > > > >  static int i3c_device_remove(struct device *dev)
> > > > >  {
> > > > >  	struct i3c_device *i3cdev = dev_to_i3cdev(dev);
> > > > > @@ -462,6 +490,42 @@ static int i3c_bus_init(struct i3c_bus *i3cbus)
> > > > >  	return 0;
> > > > >  }
> > > > >  
> > > > > +static int
> > > > > +i3c_master_request_mastership_locked(struct i3c_master_controller *master)
> > > > > +{
> > > > > +	if (WARN_ON(master->init_done &&
> > > > > +	    !rwsem_is_locked(&master->bus.lock)))
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	if (!master->ops->request_mastership)
> > > > > +		return -ENOTSUPP;
> > > > > +
> > > > > +	return master->ops->request_mastership(master);
> > > > > +}
> > > > > +
> > > > > +static int i3c_master_owns_bus(struct i3c_master_controller *master)
> > > > > +{
> > > > > +	return (master->bus.cur_master == master->this);
> > > > > +}
> > > > > +
> > > > > +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master)
> > > > > +{
> > > > > +	int ret;
> > > > > +
> > > > > +	if (!i3c_master_owns_bus(master)) {
> > > > > +		i3c_bus_normaluse_unlock(&master->bus);
> > > > > +		i3c_bus_maintenance_lock(&master->bus);
> > > > > +
> > > > > +		ret = i3c_master_request_mastership_locked(master);
> > > > > +		if (ret) {
> > > > > +			i3c_bus_maintenance_unlock(&master->bus);
> > > > > +			return ret;
> > > > > +		}
> > > > > +		i3c_bus_downgrade_maintenance_lock(&master->bus);
> > > > > +	}
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > >  static const char * const i3c_bus_mode_strings[] = {
> > > > >  	[I3C_BUS_MODE_PURE] = "pure",
> > > > >  	[I3C_BUS_MODE_MIXED_FAST] = "mixed-fast",
> > > > > @@ -636,6 +700,22 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
> > > > >  	return dev;
> > > > >  }
> > > > >  
> > > > > +static struct i2c_dev_desc *
> > > > > +i3c_master_alloc_i2c_dev_no_boardinfo(struct i3c_master_controller *master,
> > > > > +				      u16 addr, u8 lvr)
> > > > 
> > > > u8 addr.
> > > > 
> > > 
> > > Originaly I2C address is u16 but we can change it as we know DEFSLVS does not
> > > support 10bit addresses.
> > > 
> > > > > +{
> > > > > +	struct i2c_dev_desc *dev;
> > > > > +
> > > > > +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> > > > > +	if (!dev)
> > > > > +		return ERR_PTR(-ENOMEM);
> > > > > +
> > > > > +	dev->common.master = master;
> > > > > +	dev->addr = addr;
> > > > > +	dev->lvr = lvr;
> > > > > +
> > > > > +	return dev;
> > > > > +}
> > > > >  static void *i3c_ccc_cmd_dest_init(struct i3c_ccc_cmd_dest *dest, u8 addr,
> > > > >  				   u16 payloadlen)
> > > > >  {
> > > > > @@ -705,6 +785,8 @@ i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master,
> > > > >  	struct i2c_dev_desc *dev;
> > > > >  
> > > > >  	i3c_bus_for_each_i2cdev(&master->bus, dev) {
> > > > > +		if (!dev->boardinfo)
> > > > > +			continue;
> > > > >  		if (dev->boardinfo->base.addr == addr)
> > > > >  			return dev;
> > > > >  	}
> > > > > @@ -1478,7 +1560,8 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
> > > > >  		return;
> > > > >  
> > > > >  	i3c_bus_for_each_i3cdev(&master->bus, desc) {
> > > > > -		if (desc->dev || !desc->info.dyn_addr || desc == master->this)
> > > > > +		if (desc->dev || !desc->info.dyn_addr ||
> > > > > +		    desc == master->this || !desc->info.pid)
> > > > >  			continue;
> > > > >  
> > > > >  		desc->dev = kzalloc(sizeof(*desc->dev), GFP_KERNEL);
> > > > > @@ -1504,6 +1587,69 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
> > > > >  	}
> > > > >  }
> > > > >  
> > > > > +static struct i2c_dev_boardinfo *
> > > > > +i3c_master_find_i2c_boardinfo(const struct i3c_master_controller *master,
> > > > > +			      u16 addr, u8 lvr)
> > > > 
> > > > Same.
> > > > 
> > > 
> > > Same :-)
> > > 
> > > > > +{
> > > > > +	struct i2c_dev_boardinfo *i2cboardinfo;
> > > > > +
> > > > > +	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
> > > > > +		if (i2cboardinfo->base.addr == addr &&
> > > > > +		    i2cboardinfo->lvr == lvr)
> > > > > +			return i2cboardinfo;
> > > > > +	}
> > > > > +
> > > > > +	return NULL;
> > > > > +}
> > > > > +
> > > > > +static void
> > > > > +i3c_master_register_new_i2c_devs(struct i3c_master_controller *master)
> > > > > +{
> > > > > +	struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
> > > > > +	struct i2c_dev_desc *i2cdev;
> > > > > +
> > > > > +	if (!master->init_done)
> > > > > +		return;
> > > > > +
> > > > > +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> > > > > +
> > > > > +		if (i2cdev->dev)
> > > > > +			continue;
> > > > > +
> > > > > +		if (!i2cdev->boardinfo)
> > > > > +			continue;
> > > > > +
> > > > > +		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
> > > > > +	}
> > > > > +}
> > > > > +
> > > > > +static int i3c_master_get_accmst_locked(struct i3c_master_controller *master,
> > > > > +					u8 addr)
> > > > > +{
> > > > > +	struct i3c_ccc_getaccmst *accmst;
> > > > > +	struct i3c_ccc_cmd_dest dest;
> > > > > +	struct i3c_ccc_cmd cmd;
> > > > > +	int ret;
> > > > > +
> > > > > +	accmst = i3c_ccc_cmd_dest_init(&dest, addr, sizeof(*accmst));
> > > > > +	if (!accmst)
> > > > > +		return -ENOMEM;
> > > > > +
> > > > > +	i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETACCMST, &dest, 1);
> > > > > +
> > > > > +	ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
> > > > > +	if (ret)
> > > > > +		goto out;
> > > > > +
> > > > > +	if (dest.payload.len != sizeof(*accmst))
> > > > > +		ret = -EIO;
> > > > > +
> > > > > +out:
> > > > > +	i3c_ccc_cmd_dest_cleanup(&dest);
> > > > > +
> > > > > +	return ret;
> > > > > +}
> > > > > +EXPORT_SYMBOL_GPL(i3c_master_get_accmst_locked);
> > > > >  /**
> > > > >   * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
> > > > >   * @master: master doing the DAA
> > > > > @@ -1548,10 +1694,6 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
> > > > >  	if (!i3c_bus_dev_addr_is_avail(&master->bus, info->dyn_addr))
> > > > >  		return -EINVAL;
> > > > >  
> > > > > -	if (I3C_BCR_DEVICE_ROLE(info->bcr) == I3C_BCR_I3C_MASTER &&
> > > > > -	    master->secondary)
> > > > > -		return -EINVAL;
> > > > > -
> > > > >  	if (master->this)
> > > > >  		return -EINVAL;
> > > > >  
> > > > > @@ -1560,7 +1702,8 @@ static int i3c_master_set_info(struct i3c_master_controller *master,
> > > > >  		return PTR_ERR(i3cdev);
> > > > >  
> > > > >  	master->this = i3cdev;
> > > > > -	master->bus.cur_master = master->this;
> > > > > +	if (!secondary)
> > > > > +		master->bus.cur_master = master->this;
> > > > >  
> > > > >  	ret = i3c_master_attach_i3c_dev(master, i3cdev);
> > > > >  	if (ret)
> > > > > @@ -1601,37 +1744,7 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
> > > > >  	}
> > > > >  }
> > > > >  
> > > > > -/**
> > > > > - * i3c_master_bus_init() - initialize an I3C bus
> > > > > - * @master: main master initializing the bus
> > > > > - *
> > > > > - * This function is following all initialisation steps described in the I3C
> > > > > - * specification:
> > > > > - *
> > > > > - * 1. Attach I2C and statically defined I3C devs to the master so that the
> > > > > - *    master can fill its internal device table appropriately
> > > > > - *
> > > > > - * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
> > > > > - *    the master controller. That's usually where the bus mode is selected
> > > > > - *    (pure bus or mixed fast/slow bus)
> > > > > - *
> > > > > - * 3. Instruct all devices on the bus to drop their dynamic address. This is
> > > > > - *    particularly important when the bus was previously configured by someone
> > > > > - *    else (for example the bootloader)
> > > > > - *
> > > > > - * 4. Disable all slave events.
> > > > > - *
> > > > > - * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
> > > > > - *    devices that have a static address
> > > > > - *
> > > > > - * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
> > > > > - *    remaining I3C devices
> > > > > - *
> > > > > - * Once this is done, all I3C and I2C devices should be usable.
> > > > > - *
> > > > > - * Return: a 0 in case of success, an negative error code otherwise.
> > > > > - */
> > > > > -static int i3c_master_bus_init(struct i3c_master_controller *master)
> > > > > +static int i3c_master_attach_static_devs(struct i3c_master_controller *master)
> > > > >  {
> > > > >  	enum i3c_addr_slot_status status;
> > > > >  	struct i2c_dev_boardinfo *i2cboardinfo;
> > > > > @@ -1640,32 +1753,24 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
> > > > >  	struct i2c_dev_desc *i2cdev;
> > > > >  	int ret;
> > > > >  
> > > > > -	/*
> > > > > -	 * First attach all devices with static definitions provided by the
> > > > > -	 * FW.
> > > > > -	 */
> > > > >  	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
> > > > >  		status = i3c_bus_get_addr_slot_status(&master->bus,
> > > > >  						      i2cboardinfo->base.addr);
> > > > > -		if (status != I3C_ADDR_SLOT_FREE) {
> > > > > -			ret = -EBUSY;
> > > > > -			goto err_detach_devs;
> > > > > -		}
> > > > > +		if (status != I3C_ADDR_SLOT_FREE)
> > > > > +			return -EBUSY;
> > > > >  
> > > > >  		i3c_bus_set_addr_slot_status(&master->bus,
> > > > >  					     i2cboardinfo->base.addr,
> > > > >  					     I3C_ADDR_SLOT_I2C_DEV);
> > > > >  
> > > > >  		i2cdev = i3c_master_alloc_i2c_dev(master, i2cboardinfo);
> > > > > -		if (IS_ERR(i2cdev)) {
> > > > > -			ret = PTR_ERR(i2cdev);
> > > > > -			goto err_detach_devs;
> > > > > -		}
> > > > > +		if (IS_ERR(i2cdev))
> > > > > +			return PTR_ERR(i2cdev);
> > > > >  
> > > > >  		ret = i3c_master_attach_i2c_dev(master, i2cdev);
> > > > >  		if (ret) {
> > > > >  			i3c_master_free_i2c_dev(i2cdev);
> > > > > -			goto err_detach_devs;
> > > > > +			return ret;
> > > > >  		}
> > > > >  	}
> > > > >  	list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) {
> > > > > @@ -1676,27 +1781,68 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
> > > > >  		if (i3cboardinfo->init_dyn_addr) {
> > > > >  			status = i3c_bus_get_addr_slot_status(&master->bus,
> > > > >  						i3cboardinfo->init_dyn_addr);
> > > > > -			if (status != I3C_ADDR_SLOT_FREE) {
> > > > > -				ret = -EBUSY;
> > > > > -				goto err_detach_devs;
> > > > > -			}
> > > > > +			if (status != I3C_ADDR_SLOT_FREE)
> > > > > +				return -EBUSY;
> > > > >  		}
> > > > >  
> > > > >  		i3cdev = i3c_master_alloc_i3c_dev(master, &info);
> > > > > -		if (IS_ERR(i3cdev)) {
> > > > > -			ret = PTR_ERR(i3cdev);
> > > > > -			goto err_detach_devs;
> > > > > -		}
> > > > > +		if (IS_ERR(i3cdev))
> > > > > +			return PTR_ERR(i3cdev);
> > > > >  
> > > > >  		i3cdev->boardinfo = i3cboardinfo;
> > > > >  
> > > > >  		ret = i3c_master_attach_i3c_dev(master, i3cdev);
> > > > >  		if (ret) {
> > > > >  			i3c_master_free_i3c_dev(i3cdev);
> > > > > -			goto err_detach_devs;
> > > > > +			return ret;
> > > > >  		}
> > > > >  	}
> > > > >  
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +/**
> > > > > + * i3c_master_bus_init() - initialize an I3C bus
> > > > > + * @master: main master initializing the bus
> > > > > + *
> > > > > + * This function is following all initialisation steps described in the I3C
> > > > > + * specification:
> > > > > + *
> > > > > + * 1. Attach I2C and statically defined I3C devs to the master so that the
> > > > > + *    master can fill its internal device table appropriately
> > > > > + *
> > > > > + * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
> > > > > + *    the master controller. That's usually where the bus mode is selected
> > > > > + *    (pure bus or mixed fast/slow bus)
> > > > > + *
> > > > > + * 3. Instruct all devices on the bus to drop their dynamic address. This is
> > > > > + *    particularly important when the bus was previously configured by someone
> > > > > + *    else (for example the bootloader)
> > > > > + *
> > > > > + * 4. Disable all slave events.
> > > > > + *
> > > > > + * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
> > > > > + *    devices that have a static address
> > > > > + *
> > > > > + * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
> > > > > + *    remaining I3C devices
> > > > > + *
> > > > > + * Once this is done, all I3C and I2C devices should be usable.
> > > > > + *
> > > > > + * Return: a 0 in case of success, an negative error code otherwise.
> > > > > + */
> > > > > +static int i3c_master_bus_init(struct i3c_master_controller *master)
> > > > > +{
> > > > > +	struct i3c_dev_desc *i3cdev;
> > > > > +	int ret;
> > > > > +
> > > > > +	/*
> > > > > +	 * First attach all devices with static definitions provided by the
> > > > > +	 * FW.
> > > > > +	 */
> > > > > +	ret = i3c_master_attach_static_devs(master);
> > > > > +	if (ret)
> > > > > +		goto err_detach_devs;
> > > > >  	/*
> > > > >  	 * Now execute the controller specific ->bus_init() routine, which
> > > > >  	 * might configure its internal logic to match the bus limitations.
> > > > > @@ -1780,45 +1926,76 @@ i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev)
> > > > >  }
> > > > >  
> > > > >  /**
> > > > > - * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> > > > > - * @master: master used to send frames on the bus
> > > > > - * @addr: I3C slave dynamic address assigned to the device
> > > > > + * i3c_master_add_i2c_dev_locked() - add an I2C slave to the bus
> > > > > + * @master: master used to register I2C device
> > > > > + * @addr: I2C device address
> > > > > + * @lvr: legacy virtual register value
> > > > >   *
> > > > > - * This function is instantiating an I3C device object and adding it to the
> > > > > - * I3C device list. All device information are automatically retrieved using
> > > > > - * standard CCC commands.
> > > > > - *
> > > > > - * The I3C device object is returned in case the master wants to attach
> > > > > - * private data to it using i3c_dev_set_master_data().
> > > > > + * This function is instantiating an I2C device object and adding it to the
> > > > > + * I2C device list.
> > > > >   *
> > > > >   * This function must be called with the bus lock held in write mode.
> > > > >   *
> > > > >   * Return: a 0 in case of success, an negative error code otherwise.
> > > > >   */
> > > > > -int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > > > -				  u8 addr)
> > > > > +int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
> > > > > +				  u16 addr, u8 lvr)
> > > > >  {
> > > > > -	struct i3c_device_info info = { .dyn_addr = addr };
> > > > > -	struct i3c_dev_desc *newdev, *olddev;
> > > > > -	u8 old_dyn_addr = addr, expected_dyn_addr;
> > > > > -	struct i3c_ibi_setup ibireq = { };
> > > > > -	bool enable_ibi = false;
> > > > > +	enum i3c_addr_slot_status status;
> > > > > +	struct i2c_dev_desc *i2cdev;
> > > > >  	int ret;
> > > > >  
> > > > >  	if (!master)
> > > > >  		return -EINVAL;
> > > > >  
> > > > > -	newdev = i3c_master_alloc_i3c_dev(master, &info);
> > > > > -	if (IS_ERR(newdev))
> > > > > -		return PTR_ERR(newdev);
> > > > > +	status = i3c_bus_get_addr_slot_status(&master->bus,
> > > > > +					      addr);
> > > > > +	if (status != I3C_ADDR_SLOT_FREE)
> > > > > +		return -EBUSY;
> > > > >  
> > > > > -	ret = i3c_master_attach_i3c_dev(master, newdev);
> > > > > -	if (ret)
> > > > > +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> > > > > +				     I3C_ADDR_SLOT_I2C_DEV);
> > > > > +
> > > > > +	i2cdev = i3c_master_alloc_i2c_dev_no_boardinfo(master, addr, lvr);
> > > > > +
> > > > > +	if (IS_ERR(i2cdev)) {
> > > > > +		ret = PTR_ERR(i2cdev);
> > > > > +		goto err_free_dev;
> > > > > +	}
> > > > > +
> > > > > +	i2cdev->boardinfo = i3c_master_find_i2c_boardinfo(master, addr, lvr);
> > > > > +
> > > > > +	ret = i3c_master_attach_i2c_dev(master, i2cdev);
> > > > > +
> > > > > +	if (ret) {
> > > > > +		ret = PTR_ERR(i2cdev);
> > > > >  		goto err_free_dev;
> > > > > +	}
> > > > > +
> > > > > +	return 0;
> > > > > +
> > > > > +err_free_dev:
> > > > > +	i3c_bus_set_addr_slot_status(&master->bus, addr,
> > > > > +				     I3C_ADDR_SLOT_FREE);
> > > > > +	i3c_master_free_i2c_dev(i2cdev);
> > > > > +
> > > > > +	return ret;
> > > > > +}
> > > > > +EXPORT_SYMBOL_GPL(i3c_master_add_i2c_dev_locked);
> > > > > +
> > > > > +static int
> > > > > +i3c_master_retrieve_info_and_reuse(struct i3c_master_controller *master,
> > > > > +				   struct i3c_dev_desc *newdev)
> > > > > +{
> > > > > +	struct i3c_dev_desc *olddev;
> > > > > +	u8 old_dyn_addr = newdev->info.dyn_addr, expected_dyn_addr;
> > > > > +	struct i3c_ibi_setup ibireq = { };
> > > > > +	bool enable_ibi = false;
> > > > > +	int ret;
> > > > >  
> > > > >  	ret = i3c_master_retrieve_dev_info(newdev);
> > > > >  	if (ret)
> > > > > -		goto err_detach_dev;
> > > > > +		return ret;
> > > > >  
> > > > >  	olddev = i3c_master_search_i3c_dev_duplicate(newdev);
> > > > >  	if (olddev) {
> > > > > @@ -1857,7 +2034,7 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > > >  
> > > > >  	ret = i3c_master_reattach_i3c_dev(newdev, old_dyn_addr);
> > > > >  	if (ret)
> > > > > -		goto err_detach_dev;
> > > > > +		return ret;
> > > > >  
> > > > >  	/*
> > > > >  	 * Depending on our previous state, the expected dynamic address might
> > > > > @@ -1920,6 +2097,50 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > > >  	}
> > > > >  
> > > > >  	return 0;
> > > > > +}
> > > > > +
> > > > > +/**
> > > > > + * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
> > > > > + * @master: master used to send frames on the bus
> > > > > + * @addr: I3C slave dynamic address assigned to the device
> > > > > + *
> > > > > + * This function is instantiating an I3C device object and adding it to the
> > > > > + * I3C device list. All device information are automatically retrieved using
> > > > > + * standard CCC commands.
> > > > > + *
> > > > > + * The I3C device object is returned in case the master wants to attach
> > > > > + * private data to it using i3c_dev_set_master_data().
> > > > > + *
> > > > > + * This function must be called with the bus lock held in write mode.
> > > > > + *
> > > > > + * Return: a 0 in case of success, an negative error code otherwise.
> > > > > + */
> > > > > +int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > > > +				  u8 addr)
> > > > > +{
> > > > > +	struct i3c_device_info info = { .dyn_addr = addr };
> > > > > +	struct i3c_dev_desc *newdev;
> > > > > +	int ret;
> > > > > +
> > > > > +	if (!master)
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	newdev = i3c_master_alloc_i3c_dev(master, &info);
> > > > > +	if (IS_ERR(newdev))
> > > > > +		return PTR_ERR(newdev);
> > > > > +
> > > > > +	ret = i3c_master_attach_i3c_dev(master, newdev);
> > > > > +	if (ret)
> > > > > +		goto err_free_dev;
> > > > > +
> > > > > +	if (i3c_master_owns_bus(master)) {
> > > > > +		ret = i3c_master_retrieve_info_and_reuse(master, newdev);
> > > > > +		if (ret)
> > > > > +			goto err_detach_dev;
> > > > > +	} else
> > > > > +		master->want_to_acquire_bus = true;
> > > > > +
> > > > > +	return 0;
> > > > >  
> > > > >  err_detach_dev:
> > > > >  	if (newdev->dev && newdev->dev->desc)
> > > > > @@ -2101,11 +2322,15 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
> > > > >  	}
> > > > >  
> > > > >  	i3c_bus_normaluse_lock(&master->bus);
> > > > > +	ret = i3c_master_acquire_bus_ownership(master);
> > > > > +	if (ret)
> > > > > +		goto err_unlock_bus;
> > > > >  	dev = i3c_master_find_i2c_dev_by_addr(master, addr);
> > > > >  	if (!dev)
> > > > >  		ret = -ENOENT;
> > > > >  	else
> > > > >  		ret = master->ops->i2c_xfers(dev, xfers, nxfers);
> > > > > +err_unlock_bus:
> > > > >  	i3c_bus_normaluse_unlock(&master->bus);
> > > > >  
> > > > >  	return ret ? ret : nxfers;
> > > > > @@ -2144,9 +2369,12 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
> > > > >  	 * We silently ignore failures here. The bus should keep working
> > > > >  	 * correctly even if one or more i2c devices are not registered.
> > > > >  	 */
> > > > > -	i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
> > > > > +	i3c_bus_for_each_i2cdev(&master->bus, i2cdev) {
> > > > > +		if (!i2cdev->boardinfo)
> > > > > +			continue;
> > > > >  		i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
> > > > >  
> > > > > +	}
> > > > >  	return 0;
> > > > >  }
> > > > >  
> > > > > @@ -2385,9 +2613,76 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
> > > > >  	     !ops->recycle_ibi_slot))
> > > > >  		return -EINVAL;
> > > > >  
> > > > > +	/*
> > > > > +	 * If mastership request is supported, we also need hooks to control
> > > > > +	 * when mastership request can occur by enabling/disabling the event.
> > > > > +	 */
> > > > > +	if (ops->request_mastership &&
> > > > > +	    (!ops->enable_mr_events || !ops->disable_mr_events))
> > > > > +		return -EINVAL;
> > > > >  	return 0;
> > > > >  }
> > > > >  
> > > > > +static void i3c_master_register_new_devs(struct i3c_master_controller *master)
> > > > > +{
> > > > > +	/*
> > > > > +	 * We can register devices received from master by DEFSLVS.
> > > > > +	 */
> > > > > +	i3c_bus_normaluse_lock(&master->bus);
> > > > > +	i3c_master_register_new_i3c_devs(master);
> > > > > +	i3c_master_register_new_i2c_devs(master);
> > > > > +	i3c_bus_normaluse_unlock(&master->bus);
> > > > > +}
> > > > > +
> > > > > +/**
> > > > > + * i3c_master_bus_takeover() - register new I3C devices on bus takeover
> > > > > + * @master: master used to send frames on the bus
> > > > > + *
> > > > > + * This function is useful when devices were not added
> > > > > + * during initialization or when new device joined the bus
> > > > > + * which wasn't under our control.
> > > > > + */
> > > > > +void i3c_master_bus_takeover(struct i3c_master_controller *master)
> > > > > +{
> > > > > +	struct i3c_dev_desc *i3cdev, *i3ctmp;
> > > > > +	int ret;
> > > > > +
> > > > > +	master->want_to_acquire_bus = false;
> > > > 
> > > > Can you explain the usage of this variable?
> > > > 
> > > 
> > > The idea of this was to let HC know that we want to acquire the bus after
> > > ENEC(MR) received in slave mode.
> > 
> > With the logic that I proposed you don't need this. When received ENEC 
> > you will try to get the bus ownership if HC not fully initialized or have 
> > DEFSLVS to add, otherwise you don't need to get the bus ownership.
> 
> In case devices on the bus are the same, I agree. But please consider the case
> when slave joins the bus (Hot-Join) and MR event is disabled for now, our
> secondary master receives DEFSLVS, we add that device to the subsystem but
> cannot request mastership yet. We need a flag to indicate that we should
> request mastership on next ENEC(MR). It doesn't make sense to request
> mastership every time when ENEC(MR) is received.

At least I think you can give a mean for the flag name, otherwise it is 
not clear why sec master want bus ownership.

> 
> > 
> > > 
> > > > > +
> > > > > +	if (!master->init_done)
> > > > > +		return;
> > > > > +
> > > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > > +	master->ops->populate_bus(master);
> > > > > +
> > > > > +	list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c,
> > > > > +				 common.node) {
> > > > > +		if (i3cdev->info.pid)
> > > > > +			continue;
> > > > > +
> > > > > +		ret = i3c_master_retrieve_info_and_reuse(master, i3cdev);
> > > > > +		if (ret) {
> > > > > +			if (i3cdev->dev && i3cdev->dev->desc)
> > > > > +				i3cdev->dev->desc = NULL;
> > > > > +
> > > > > +			i3c_master_detach_i3c_dev(i3cdev);
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	/*
> > > > > +	 * If current master finished bus initialization properly, we can
> > > > > +	 * enable Mastership event.
> > > > > +	 */
> > > > > +	ret = i3c_master_enable_mr_events_locked(master);
> > > > > +	if (ret)
> > > > > +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> > > > > +
> > > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > > > +
> > > > > +	i3c_master_register_new_devs(master);
> > > > > +}
> > > > > +EXPORT_SYMBOL_GPL(i3c_master_bus_takeover);
> > > > > +
> > > > >  /**
> > > > >   * i3c_master_init() - initializes all the structures required by I3C master
> > > > >   * @master: master used to send frames on the bus
> > > > > @@ -2417,9 +2712,6 @@ int i3c_master_init(struct i3c_master_controller *master,
> > > > >  	struct i2c_dev_boardinfo *i2cbi;
> > > > >  	int ret;
> > > > >  
> > > > > -	/* We do not support secondary masters yet. */
> > > > > -	if (secondary)
> > > > > -		return -ENOTSUPP;
> > > > >  
> > > > >  	ret = i3c_master_check_ops(ops);
> > > > >  	if (ret)
> > > > > @@ -2432,6 +2724,7 @@ int i3c_master_init(struct i3c_master_controller *master,
> > > > >  	master->dev.release = i3c_masterdev_release;
> > > > >  	master->ops = ops;
> > > > >  	master->secondary = secondary;
> > > > > +	master->want_to_acquire_bus = secondary;
> > > > >  	INIT_LIST_HEAD(&master->boardinfo.i2c);
> > > > >  	INIT_LIST_HEAD(&master->boardinfo.i3c);
> > > > >  
> > > > > @@ -2488,6 +2781,92 @@ void i3c_master_cleanup(struct i3c_master_controller *master)
> > > > >  EXPORT_SYMBOL_GPL(i3c_master_cleanup);
> > > > >  
> > > > >  /**
> > > > > + * i3c_secondary_master_register() - register an secondary I3C master
> > > > > + * @master: master used to send frames on the bus
> > > > > + * @info: master info, describes this device
> > > > > + *
> > > > > + * This function takes care of everything for you:
> > > > > + *
> > > > > + * - updates this master info
> > > > > + * - registers the I2C adapter
> > > > > + * - if possible, populates the bus with devices received by DEFSLVS
> > > > > + *   command
> > > > > + *
> > > > > + * Return: 0 in case of success, a negative error code otherwise.
> > > > > + */
> > > > > +int i3c_secondary_master_register(struct i3c_master_controller *master,
> > > > > +				  struct i3c_device_info *info)
> > > > > +{
> > > > > +	int ret;
> > > > > +
> > > > > +	ret = i3c_master_set_info(master, info, master->secondary);
> > > > > +	if (ret)
> > > > > +		return ret;
> > > > > +
> > > > > +	ret = master->ops->bus_init(master);
> > > > > +	if (ret)
> > > > > +		return ret;
> > > > 
> > > > At this point you don't have enough information to do the bus 
> > > > initialization.
> > > > 
> > > 
> > > Actually, current ->bus_init() implementations (in CDNS and DW) does not
> > > initialize the bus. We are just setting the mode, configuring some init values
> > > in the registers and enabling the core. Maybe we should rename it?
> > 
> > The name for me its ok. My point was that when you call 
> > i3c_secondary_master_register() in CDNS you don't have yet DEFSLVS 
> > information.
> 
> It depends. When current master did not initialize the bus yet, this is true.
> But when master and the bus are already initialized, I have DEFSLVS. Different
> story is that devices aren't added to the subsystem yet. So what I have do in
> that case is to enable to let HC operate and populate the bus later (using
> ->populate_bus() hook)

Ahh I didn't see, you are calling it in two different places. Does it 
make sense?

It is more logical to do the secondary_master_register() after get the 
bus ownership (just need the first time), otherwise the HC is just a 
slave.

> 
> > 
> > > 
> > > > > +
> > > > > +	ret = device_add(&master->dev);
> > > > > +	if (ret)
> > > > > +		return -1;
> > > > > +
> > > > > +	/*
> > > > > +	 * Expose our I3C bus as an I2C adapter so that I2C devices are exposed
> > > > > +	 * through the I2C subsystem.
> > > > > +	 */
> > > > > +	ret = i3c_master_i2c_adapter_init(master);
> > > > > +	if (ret)
> > > > > +		goto err_del_dev;
> > > > > +
> > > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > > +	/*
> > > > > +	 * If possible, request mastership and try to populate the bus.
> > > > > +	 */
> > > > > +	ret = i3c_master_request_mastership_locked(master);
> > > > > +	if (ret)
> > > > > +		dev_warn(&master->dev,
> > > > > +			 "Mastership failed at init time (ret = %i)", ret);
> > > > > +
> > > > > +	/*
> > > > > +	 * No matter if mastership takeover passed or not, add partialy
> > > > > +	 * discovered devices. We can register them when ENEC(MR) is enabled.
> > > > > +	 */
> > > > > +	master->ops->populate_bus(master);
> > > > > +
> > > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > > > +
> > > > > +	/*
> > > > > +	 * We're done initializing the bus and the controller, we can now
> > > > > +	 * register I3C devices obtained by DEFSLVS.
> > > > > +	 */
> > > > > +	master->init_done = true;
> > > > > +	i3c_master_register_new_devs(master);
> > > > > +
> > > > > +	/*
> > > > > +	 * If we are owning the bus, enable ENEC(MR) to let other masters
> > > > > +	 * initialize their bus.
> > > > > +	 */
> > > > > +	if (i3c_master_owns_bus(master)) {
> > > > > +		i3c_bus_maintenance_lock(&master->bus);
> > > > > +		ret = i3c_master_enable_mr_events_locked(master);
> > > > > +		i3c_bus_maintenance_unlock(&master->bus);
> > > > > +		if (ret)
> > > > > +			dev_warn(&master->dev,
> > > > > +				 "ENEC(MR) failed (ret = %i)", ret);
> > > > > +	}
> > > > > +
> > > > > +
> > > > > +	return 0;
> > > > > +
> > > > > +err_del_dev:
> > > > > +	device_del(&master->dev);
> > > > > +
> > > > > +	return ret;
> > > > > +}
> > > > > +EXPORT_SYMBOL_GPL(i3c_secondary_master_register);
> > > > > +
> > > > > +/**
> > > > >   * i3c_master_register() - register an primary I3C master
> > > > >   * @master: master used to send frames on the bus
> > > > >   * @info: master info, describes this device
> > > > > @@ -2509,7 +2888,6 @@ int i3c_master_register(struct i3c_master_controller *master,
> > > > >  	ret = i3c_master_set_info(master, info, master->secondary);
> > > > >  	if (ret)
> > > > >  		return ret;
> > > > > -
> > > > >  	ret = i3c_master_bus_init(master);
> > > > >  	if (ret)
> > > > >  		return ret;
> > > > > @@ -2535,6 +2913,16 @@ int i3c_master_register(struct i3c_master_controller *master,
> > > > >  	i3c_master_register_new_i3c_devs(master);
> > > > >  	i3c_bus_normaluse_unlock(&master->bus);
> > > > >  
> > > > > +	/*
> > > > > +	 * Enable ENEC(MR) and let other masters request mastership
> > > > > +	 * and initialize their bus.
> > > > > +	 */
> > > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > > +	ret = i3c_master_enable_mr_events_locked(master);
> > > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > > > +	if (ret)
> > > > > +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> > > > > +
> > > > >  	return 0;
> > > > >  
> > > > >  err_del_dev:
> > > > > @@ -2548,6 +2936,29 @@ int i3c_master_register(struct i3c_master_controller *master,
> > > > >  EXPORT_SYMBOL_GPL(i3c_master_register);
> > > > >  
> > > > >  /**
> > > > > + * i3c_master_mastership_ack() - acknowledges bus takeover.
> > > > > + * @master: master used to send frames on the bus
> > > > > + * @addr: I3C device address
> > > > > + *
> > > > > + * This function acknowledges bus takeover.
> > > > > + *
> > > > > + * Return: 0 in case of success, a negative error code otherwise.
> > > > > + */
> > > > > +int i3c_master_mastership_ack(struct i3c_master_controller *master,
> > > > > +			      u8 addr)
> > > > > +{
> > > > > +	int ret;
> > > > > +
> > > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > > +	ret = i3c_master_get_accmst_locked(master, addr);
> > > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > > > +
> > > > > +	return ret;
> > > > > +}
> > > > > +EXPORT_SYMBOL_GPL(i3c_master_mastership_ack);
> > > > > +
> > > > > +
> > > > > +/**
> > > > >   * i3c_master_unregister() - unregister an I3C master
> > > > >   * @master: master used to send frames on the bus
> > > > >   *
> > > > > @@ -2557,6 +2968,9 @@ EXPORT_SYMBOL_GPL(i3c_master_register);
> > > > >   */
> > > > >  int i3c_master_unregister(struct i3c_master_controller *master)
> > > > >  {
> > > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > > +	i3c_master_disable_mr_events(master);
> > > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > > >  	i3c_master_i2c_adapter_cleanup(master);
> > > > >  	i3c_master_unregister_i3c_devs(master);
> > > > >  	i3c_master_bus_cleanup(master);
> > > > > diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
> > > > > index e089771..6ac9b46 100644
> > > > > --- a/include/linux/i3c/master.h
> > > > > +++ b/include/linux/i3c/master.h
> > > > > @@ -421,6 +421,26 @@ struct i3c_bus {
> > > > >   *		      for a future IBI
> > > > >   *		      This method is mandatory only if ->request_ibi is not
> > > > >   *		      NULL.
> > > > > + * @request_mastership: requests bus mastership. Mastership is requested
> > > > > + *                      automatically when device driver wants to transfer
> > > > > + *                      data using a master that does not currently
> > > > > + *                      owns the bus.
> > > > > + * @enable_mr_events: enable the Mastership event. Master driver can prepare
> > > > > + *                    its internal state to be ready for incoming mastership
> > > > > + *                    requests and then should send ENEC(MR) command to let
> > > > > + *                    other masters take control over the bus.
> > > > > + * @disable_mr_events: disable the Mastership event. Master driver should
> > > > > + *                     immediately send DISEC(MR) command and can perform other
> > > > > + *                     operations. For example, recycle IBI slot if used before
> > > > > + *                     for MR event.
> > > > > + * @populate_pus: populates the bus. Called after bus takeover. Secondary
> > > > > + *                master can't perform DAA procedure. This function allows to
> > > > > + *                update devices received from previous bus owner in DEFSLVS
> > > > > + *                command. Useful also when new device joins the bus controlled
> > > > > + *                by secondary master, main master will be able to add
> > > > > + *                this device after mastership takeover. Driver should also
> > > > > + *		  update bus mode when I2C device is on the bus.
> > > > > + *
> > > > >   */
> > > > >  struct i3c_master_controller_ops {
> > > > >  	int (*bus_init)(struct i3c_master_controller *master);
> > > > > @@ -447,6 +467,10 @@ struct i3c_master_controller_ops {
> > > > >  	int (*disable_ibi)(struct i3c_dev_desc *dev);
> > > > >  	void (*recycle_ibi_slot)(struct i3c_dev_desc *dev,
> > > > >  				 struct i3c_ibi_slot *slot);
> > > > > +	int (*request_mastership)(struct i3c_master_controller *master);
> > > > > +	int (*enable_mr_events)(struct i3c_master_controller *master);
> > > > > +	int (*disable_mr_events)(struct i3c_master_controller *master);
> > > > > +	int (*populate_bus)(struct i3c_master_controller *master);
> > > > >  };
> > > > >  
> > > > >  /**
> > > > > @@ -488,6 +512,7 @@ struct i3c_master_controller {
> > > > >  	} boardinfo;
> > > > >  	struct i3c_bus bus;
> > > > >  	struct workqueue_struct *wq;
> > > > > +	bool want_to_acquire_bus;
> > > > >  };
> > > > >  
> > > > >  /**
> > > > > @@ -526,6 +551,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master);
> > > > >  int i3c_master_get_free_addr(struct i3c_master_controller *master,
> > > > >  			     u8 start_addr);
> > > > >  
> > > > > +int i3c_master_add_i2c_dev_locked(struct i3c_master_controller *master,
> > > > > +				  u16 addr, u8 lvr);
> > > > >  int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
> > > > >  				  u8 addr);
> > > > >  int i3c_master_do_daa(struct i3c_master_controller *master);
> > > > > @@ -535,9 +562,14 @@ int i3c_master_init(struct i3c_master_controller *master,
> > > > >  		    const struct i3c_master_controller_ops *ops,
> > > > >  		    bool secondary);
> > > > >  void i3c_master_cleanup(struct i3c_master_controller *master);
> > > > > +int i3c_secondary_master_register(struct i3c_master_controller *master,
> > > > > +				  struct i3c_device_info *info);
> > > > >  int i3c_master_register(struct i3c_master_controller *master,
> > > > >  			struct i3c_device_info *info);
> > > > >  int i3c_master_unregister(struct i3c_master_controller *master);
> > > > > +int i3c_master_mastership_ack(struct i3c_master_controller *master,
> > > > > +			      u8 addr);
> > > > > +void i3c_master_bus_takeover(struct i3c_master_controller *master);
> > > > >  int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode);
> > > > >  
> > > > >  /**
> > > > > @@ -648,7 +680,5 @@ void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot);
> > > > >  
> > > > >  struct i3c_ibi_slot *i3c_master_get_free_ibi_slot(struct i3c_dev_desc *dev);
> > > > >  
> > > > > -void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> > > > > -void i3c_bus_maintenance_unlock(struct i3c_bus *bus);
> > > > >  
> > > > >  #endif /* I3C_MASTER_H */
> > > > > -- 
> > > > > 2.4.5
> > > > 
> > > > In generally I found this intrusive for the current eco system.
> > > > 
> > > > I propose the following:
> > > > 1 - Keep the function i3c_master_register() as is and go out before 
> > > 
> > > We had that version previously. We decided to split it.
> > 
> > You just need to split the secondary master part from it. So you can go 
> > out before i3c_master_bus_init() and keep the same function.
> 
> We discussed that with Boris and we decided to split this function in this
> version to make things clear.

My proposal isn't to much different with the advantage that it not broke 
the existing code.

> 
> > 
> > Them use i3c_secondary_master_register() when received DEFSLVS or ENEC 
> > MR.
> 
> It is also possible that our controller received DA and DEFSLVS even before
> master registration. We should try to register that, this is something I'm
> testing in my scenarios.

That shouldn't be a problem. You receive DA and them DEFSLVS.

Add DEFSLVS to the system and try to be current master.

If you get the ownership, do:
	i3c_secondary_master_register()
	retrieve defslvs info and add them to the system.

After this you will see everything in /sys/bus/i3c/devices

If you don't get the ownership, it is ok because HC is just a slave.

I would try to da all management task in subsystem.

> 
> > 
> > > 
> > > > i3c_master_bus_init() if secondary master.
> > > > @Boris Brezillon is it possible to replace device_initialize() device_add() with device_register()?
> > > > 
> > > > 2 - When received DEFSLVS commands add devices to a link list like 
> > > > boardinfo.
> > > 
> > > If DEFSLVS received devices are partialy added at init time.
> > > 
> > > >   Get bus ownership if there is DEFSLVS to add or secondary master not 
> > > > initialized. 
> > > > 
> > > > 3 - When received ENEC MR
> > > 
> > > I thought it works like that :-) When ENEC(MR) received, HC driver adds devices
> > > from DEFSLVS frame,
> > 
> > Yes, but in your case the logic is in HC. Let the subsystem do that task 
> > when you switch the role.
> > I think you did that in v1 or v2.
> 
> True, but we also decided to do this in HC. We didn't want to standardize events
> yet.
> 
> > 
> > > 
> > > >   Get bus ownership if there is DEFSLVS to add or secondary master not 
> > > > initialized.
> > > > 
> > > > 4 - When secondary master became current master.
> > > 
> > > and calls i3c_master_bus_takeover() to let subsystem gather device information
> > > and register them.
> > 
> > It  is not clear to me if it is already the current master.
> 
> Bus takeover should be performed right after we got the control over the bus. I
> don't know how to make is simpler.

Maybe I have to recheck this part.

> 
> > 
> > > 
> > > >   Attach new devices to the host controller and retrieve device info 
> > > > (same logic as in i3c_master_add_i3c_dev_locked).
> > > > 
> > > > With this approach on HC side you just need to add the secondary master 
> > > > stuff without changing the current code and leave for the subsystem the 
> > > > responsible to manage all these secondary master task.
> > > 
> > > This may be difficult for some controllers, depends where DEFSLVS device
> > > information is stored.
> > 
> > That is the main reason I want pass DEFSLVS to a list in the subsystem.
> > I think it will be common to everyone receive a notification that DEFSLVS 
> > arrived.
> 
> As I said before, I'm not sure if this is good idea or not. We are registering
> the devices in HC drivers after DAA using i3c_master_add_i3c_dev_locked() and
> this isn't the issue. I wonder why it could be the problem here. The
> difference here is only the source of the devices, not DAA but DEFSLVS.

It is different because when you received the DEFSLVS the HC isn't the 
current master.

> 
> > 
> > > I also cannot find information about that part in
> > > MIPI I3C HCI specification. This part can be vendor specific. What do you
> > > think?
> > 
> > It is not defined int v1.0
> 
> I see now that HCI spec does not cover secondary master functionality at all.
> 
> > 
> > > 
> > > > 
> > > > Let me know if this works for you.
> > > > 
> > > > 
> > > > Best regards,
> > > > Vitor Soares
> > > 
> > > -- 
> > > -- 
> > > Przemyslaw Gaj
> > 
> > Best regards,
> > Vitor Soares
> > 
> > 
> 
> -- 
> -- 
> Przemyslaw Gaj

Best regards,
Vitor Soares
_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem
  2019-07-12 11:28           ` Vitor Soares
@ 2019-08-11 10:17             ` Boris Brezillon
  2019-08-12 13:55               ` Vitor Soares
  0 siblings, 1 reply; 21+ messages in thread
From: Boris Brezillon @ 2019-08-11 10:17 UTC (permalink / raw)
  To: Vitor Soares, Przemyslaw Gaj; +Cc: linux-i3c, agolec, rafalc, bbrezillon

Hi Przemek, Vitor,

Sorry for the late reply.

On Fri, 12 Jul 2019 11:28:36 +0000
Vitor Soares <Vitor.Soares@synopsys.com> wrote:

> > > > > > ---
> > > > > > 
> > > > > > Main changes between v4 and v5:
> > > > > > - Add function to test if master owns the bus
> > > > > > - Add i3c_secondary_master_register() function
> > > > > > - Add populate_bus() hook to populate the bus after mastership takeover  
> > > > > 
> > > > > For me this task is for the sub-system not the host controller.
> > > > >   
> > > > 
> > > > I'm not sure where device information is stored in DW controller but in CDNS
> > > > controller DEFSLVS frame is processed in the device and the only thing I got is
> > > > information that DEFSLVS came in.   
> > > 
> > > When you receive this notification you can add the device to subsystem to 
> > > be initialized later when get bus ownership.  
> > 
> > I added this hook mostly because we have to lock the bus during devices
> > addition. If we pass DEFSLVS devices information to the system in some
> > structure, we should be ok. We can lock the bus in the framework and register
> > all the devices. But I still don't feel this is good solution, I'll have to
> > do the job once again which HW did before  
> 
> Your HW just fill a table with the DEFSLVS data and you still have to 
> access, retrieve the information and attached to the controller (same 
> approach as DAA).
> 
> If all these management is passed to the subsystem it will be more easy 
> to maintain and HC agonistic.
> 
> > 
> > @Boris, what do you think about that?

If there's nothing HW specific in ->populate_bus(), then yes, it makes
sense to have it done in the core based on information extracted from
the DEFSLVS frame.

> >   
> > >   
> > > > I need to inform subsystem that there are new
> > > > device (if any).
> > > > I remember we talkad about that already, you have access to
> > > > DEFSLVS information directly, correct?  
> > > 
> > > I can process it in the HC driver, but my point is that I want to rely it 
> > > to the subsystem the bus population with the function already present.
> > >   
> > 
> > So, do you want to pack those informations back to i3c_ccc_defslvs and pass to
> > the subsystem?  
> 
> Not necessary. It can be passed addr, bcr, dcr and lvr. 
> 
> In the subsystem I think it should be a list of i3c_ccc_defslvs that 
> holds DEFSLVS information.

Sorry, I don't get what you mean here. Why would we want a list of
i3c_ccc_defslvs objects when i3c_ccc_defslvs already stores an
array of devices. I guess you meant a list of struct i3c_ccc_dev_desc
objects.

> 
> >   
> > > >   
> > > > > > - Rework device information retrieval to allow adding partialy discovered
> > > > > > devices
> > > > > > 
> > > > > > Main changes between v3 and v4:
> > > > > > - Add i3c_master_acquire_bus_ownership to acquire the bus
> > > > > > - Refactored the code
> > > > > > 
> > > > > > Main changes between v2 and v3:
> > > > > > - Add i3c_bus_downgrade_maintenance_lock() for downgrading the bus
> > > > > > lock from maintenance to normal use
> > > > > > - Add additional fields to i2c_dev_desc for DEFSLVS purpose (addr, lvr)
> > > > > > - Add i3c_master_register_new_i2c_devs() function to register I2C devices
> > > > > > - Reworked I2C devices registration on secondary master side
> > > > > > 
> > > > > > Changes in v2:
> > > > > > - Add mastership disable event hook
> > > > > > - Changed name of mastership enable event hook
> > > > > > - Add function to test if master owns the bus
> > > > > > - Removed op_mode
> > > > > > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > > > > > pass full i3c_device_info
> > > > > > - Changed name of mastership enable event hook
> > > > > > - Add function to test if master owns the bus
> > > > > > - Removed op_mode
> > > > > > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > > > > > pass full i3c_device_info
> > > > > > - Removed redundant DEFSLVS command before GETACCMST
> > > > > > - Add i3c_master_bus_takeover function. There is a need to lock
> > > > > > the bus before adding devices and no matter of the controller
> > > > > > devices have to be added after mastership takeover.
> > > > > > - Add device registration during initialization on secondary master
> > > > > > side. Devices received by DEFSLVS (if occured). If not, device
> > > > > > initialization is deffered untill next mastership request.
> > > > > > ---
> > > > > >  drivers/i3c/device.c       |  26 ++
> > > > > >  drivers/i3c/internals.h    |   4 +
> > > > > >  drivers/i3c/master.c       | 588 ++++++++++++++++++++++++++++++++++++++-------
> > > > > >  include/linux/i3c/master.h |  34 ++-
> > > > > >  4 files changed, 563 insertions(+), 89 deletions(-)
> > > > > > 
> > > > > > diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
> > > > > > index 69cc040..b60f637 100644
> > > > > > --- a/drivers/i3c/device.c
> > > > > > +++ b/drivers/i3c/device.c
> > > > > > @@ -43,7 +43,13 @@ int i3c_device_do_priv_xfers(struct i3c_device *dev,
> > > > > >  	}
> > > > > >  
> > > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > > +	if (ret)
> > > > > > +		goto err_unlock_bus;
> > > > > > +
> > > > > >  	ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
> > > > > > +
> > > > > > +err_unlock_bus:
> > > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > > >  
> > > > > >  	return ret;
> > > > > > @@ -114,11 +120,17 @@ int i3c_device_enable_ibi(struct i3c_device *dev)
> > > > > >  	int ret = -ENOENT;
> > > > > >  
> > > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > > +	if (ret)
> > > > > > +		goto err_unlock_bus;
> > > > > > +
> > > > > >  	if (dev->desc) {
> > > > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > > > >  		ret = i3c_dev_enable_ibi_locked(dev->desc);
> > > > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > > > >  	}
> > > > > > +
> > > > > > +err_unlock_bus:
> > > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > > >  
> > > > > >  	return ret;
> > > > > > @@ -145,11 +157,17 @@ int i3c_device_request_ibi(struct i3c_device *dev,
> > > > > >  		return -EINVAL;
> > > > > >  
> > > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > > +	if (ret)
> > > > > > +		goto err_unlock_bus;
> > > > > > +
> > > > > >  	if (dev->desc) {
> > > > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > > > >  		ret = i3c_dev_request_ibi_locked(dev->desc, req);
> > > > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > > > >  	}
> > > > > > +
> > > > > > +err_unlock_bus:
> > > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > > >  
> > > > > >  	return ret;
> > > > > > @@ -166,12 +184,20 @@ EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
> > > > > >   */
> > > > > >  void i3c_device_free_ibi(struct i3c_device *dev)
> > > > > >  {
> > > > > > +	int ret;
> > > > > > +
> > > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > > +	if (ret)
> > > > > > +		goto err_unlock_bus;
> > > > > > +
> > > > > >  	if (dev->desc) {
> > > > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > > > >  		i3c_dev_free_ibi_locked(dev->desc);
> > > > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > > > >  	}
> > > > > > +
> > > > > > +err_unlock_bus:
> > > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > > >  }
> > > > > >  EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
> > > > > > diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
> > > > > > index 86b7b44..cdfc5bf 100644
> > > > > > --- a/drivers/i3c/internals.h
> > > > > > +++ b/drivers/i3c/internals.h
> > > > > > @@ -14,6 +14,10 @@ extern struct bus_type i3c_bus_type;
> > > > > >  
> > > > > >  void i3c_bus_normaluse_lock(struct i3c_bus *bus);
> > > > > >  void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
> > > > > > +void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> > > > > > +void i3c_bus_maintenance_unlock(struct i3c_bus *bus);  
> > > > > 
> > > > > These function are static.
> > > > >   
> > > > 
> > > > I forgot to revert that change to previous state.
> > > >   
> > > > > > +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master);
> > > > > > +  
> > > > > 
> > > > > What do you think to pass this logic to master.c?
> > > > >   
> > > > 
> > > > Isn't it there?  
> > > 
> > > I meant make it static and remove its call from device.c.

Can you be more specific? Where would you move the
i3c_master_acquire_bus_ownership() call? Note that we already
considered different options and the solution proposed here was the
cleanest race-free one.

> > >   
> > > >   
> > > > > >  
> > > > > >  int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
> > > > > >  				 struct i3c_priv_xfer *xfers,
> > > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> > > > > > index cbace14..3b44e66 100644
> > > > > > --- a/drivers/i3c/master.c
> > > > > > +++ b/drivers/i3c/master.c
> > > > > > @@ -93,6 +93,18 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
> > > > > >  	up_read(&bus->lock);
> > > > > >  }
> > > > > >  
> > > > > > +/*
> > > > > > + * i3c_bus_downgrade_maintenance_lock - Downgrade the bus lock to normal
> > > > > > + * operation
> > > > > > + *
> > > > > > + * Should be called when a maintenance operation is done and normal
> > > > > > + * operation is planned. See i3c_bus_maintenance_lock() and
> > > > > > + * i3c_bus_normaluse_lock() for more details.
> > > > > > + */
> > > > > > +static void i3c_bus_downgrade_maintenance_lock(struct i3c_bus *bus)
> > > > > > +{
> > > > > > +	downgrade_write(&bus->lock);
> > > > > > +}
> > > > > >  static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
> > > > > >  {
> > > > > >  	return container_of(dev, struct i3c_master_controller, dev);
> > > > > > @@ -341,6 +353,22 @@ static int i3c_device_probe(struct device *dev)
> > > > > >  	return driver->probe(i3cdev);
> > > > > >  }
> > > > > >  
> > > > > > +static int
> > > > > > +i3c_master_enable_mr_events_locked(struct i3c_master_controller *master)
> > > > > > +{
> > > > > > +	if (!master->ops->enable_mr_events)
> > > > > > +		return -ENOTSUPP;
> > > > > > +
> > > > > > +	return master->ops->enable_mr_events(master);
> > > > > > +}
> > > > > > +
> > > > > > +static void i3c_master_disable_mr_events(struct i3c_master_controller *master)
> > > > > > +{
> > > > > > +	if (!master->ops->disable_mr_events)
> > > > > > +		return;
> > > > > > +
> > > > > > +	master->ops->disable_mr_events(master);
> > > > > > +}  
> > > > > 
> > > > > Add new line.
> > > > > 
> > > > > It is not clear to me what you expect with these functions. Do you want 
> > > > > to enable MR from all devices? Just some of them? How do you decide which 
> > > > > secondary masters are allow earn the bus ownership?
> > > > >   
> > > > 
> > > > We discussed this also. For now, we enable ENEC for all masters on the bus, we
> > > > can change it later if needed.   
> > > 
> > > I would say to expand the current ibi framework to accommodate MR and  
> > 
> > Can you tell something more here? What benefits you see  
> 
> Just starting with the name. IBI stands for In Band Interrupt which can 
> be MR, HJ or SIR.
> 
> Also the concept is the same, let say you are registering a SIR w/out 
> data but in fact it is a MR.

No, it's not from a SW PoV. IBI are events I3C device drivers can
register a handler for, MR and HJ events are things the HC drivers are
expected to handle, and that's a big difference. While re-using the IBI
API to handle them should be doable I don't think it will make things
simpler.

> 
> >   
> > > also add platform entry to allow secondary masters on the bus.  
> > 
> > This is something we can consider, to select devices which can request
> > mastership. But I don't see the problem adding that later also.  
> 

Fully agree with that, that's still something we can consider
restricting afterwards. Remember that I3C is still not widely deployed
and we only have 2 controller drivers so far, so patching them should be
fairly easy if we decide to change the interface.

> 
> 
> >   
> > >   
> > > > Also, priority level is encoded in slave address
> > > > so current master will give the control to the master with lower address first.
> > > > It shouldn't be a problem.  
> > > 
> > > You can have security issues and the devices on the bus might not be 
> > > prepared to work in multi-master environment.  
> > 
> > I don't get it, can you explan what do you mean? Which devices might not be
> > prapared to work in multi-master environment, slaves? Key feature of I3C is
> > multi-master capability. Mastership request should also be transparent for pure
> > slaves on the bus. Of course, secondary masters should work in multi-master
> > configuration  
> 
> So you are probing the same hw device on two different systems. This mean 
> that in system A you can have the configuration A and in system B the 
> configuration B.
> How will you deal with this?

That's certainly something we should take care of, by restoring
previous device configs every time a bus handover happens. It will
probably involve some kind of collaboration between the core and device
drivers, because part of the configuration (everything that's set
through private SDR transfers) is only known by device users. The core
can take care of restoring IBIs config though.


> > > > > > +/**
> > > > > > + * i3c_master_bus_takeover() - register new I3C devices on bus takeover
> > > > > > + * @master: master used to send frames on the bus
> > > > > > + *
> > > > > > + * This function is useful when devices were not added
> > > > > > + * during initialization or when new device joined the bus
> > > > > > + * which wasn't under our control.
> > > > > > + */
> > > > > > +void i3c_master_bus_takeover(struct i3c_master_controller *master)
> > > > > > +{
> > > > > > +	struct i3c_dev_desc *i3cdev, *i3ctmp;
> > > > > > +	int ret;
> > > > > > +
> > > > > > +	master->want_to_acquire_bus = false;  
> > > > > 
> > > > > Can you explain the usage of this variable?
> > > > >   
> > > > 
> > > > The idea of this was to let HC know that we want to acquire the bus after
> > > > ENEC(MR) received in slave mode.  
> > > 
> > > With the logic that I proposed you don't need this. When received ENEC 
> > > you will try to get the bus ownership if HC not fully initialized or have 
> > > DEFSLVS to add, otherwise you don't need to get the bus ownership.  
> > 
> > In case devices on the bus are the same, I agree. But please consider the case
> > when slave joins the bus (Hot-Join) and MR event is disabled for now, our
> > secondary master receives DEFSLVS, we add that device to the subsystem but
> > cannot request mastership yet. We need a flag to indicate that we should
> > request mastership on next ENEC(MR). It doesn't make sense to request
> > mastership every time when ENEC(MR) is received.  
> 
> At least I think you can give a mean for the flag name, otherwise it is 
> not clear why sec master want bus ownership.

Well, I guess the idea was to use the same flag for any kind of
deferred MR requests. Not sure the reason for this MR request is really
important since the same set of actions will be done anyway. Do you have
a use case where we need to know the reason of a MR? If that's the
case, or if we want to know it for debug purpose, I'd recommend adding
extra flags to express that while keeping the want_to_acquire_bus one.

> 
> >   
> > >   
> > > >   
> > > > > > +
> > > > > > +	if (!master->init_done)
> > > > > > +		return;
> > > > > > +
> > > > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > > > +	master->ops->populate_bus(master);
> > > > > > +
> > > > > > +	list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c,
> > > > > > +				 common.node) {
> > > > > > +		if (i3cdev->info.pid)
> > > > > > +			continue;
> > > > > > +
> > > > > > +		ret = i3c_master_retrieve_info_and_reuse(master, i3cdev);
> > > > > > +		if (ret) {
> > > > > > +			if (i3cdev->dev && i3cdev->dev->desc)
> > > > > > +				i3cdev->dev->desc = NULL;
> > > > > > +
> > > > > > +			i3c_master_detach_i3c_dev(i3cdev);
> > > > > > +		}
> > > > > > +	}
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * If current master finished bus initialization properly, we can
> > > > > > +	 * enable Mastership event.
> > > > > > +	 */
> > > > > > +	ret = i3c_master_enable_mr_events_locked(master);
> > > > > > +	if (ret)
> > > > > > +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> > > > > > +
> > > > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > > > > +
> > > > > > +	i3c_master_register_new_devs(master);
> > > > > > +}
> > > > > > +EXPORT_SYMBOL_GPL(i3c_master_bus_takeover);
> > > > > > +
> > > > > >  /**
> > > > > >   * i3c_master_init() - initializes all the structures required by I3C master
> > > > > >   * @master: master used to send frames on the bus
> > > > > > @@ -2417,9 +2712,6 @@ int i3c_master_init(struct i3c_master_controller *master,
> > > > > >  	struct i2c_dev_boardinfo *i2cbi;
> > > > > >  	int ret;
> > > > > >  
> > > > > > -	/* We do not support secondary masters yet. */
> > > > > > -	if (secondary)
> > > > > > -		return -ENOTSUPP;
> > > > > >  
> > > > > >  	ret = i3c_master_check_ops(ops);
> > > > > >  	if (ret)
> > > > > > @@ -2432,6 +2724,7 @@ int i3c_master_init(struct i3c_master_controller *master,
> > > > > >  	master->dev.release = i3c_masterdev_release;
> > > > > >  	master->ops = ops;
> > > > > >  	master->secondary = secondary;
> > > > > > +	master->want_to_acquire_bus = secondary;
> > > > > >  	INIT_LIST_HEAD(&master->boardinfo.i2c);
> > > > > >  	INIT_LIST_HEAD(&master->boardinfo.i3c);
> > > > > >  
> > > > > > @@ -2488,6 +2781,92 @@ void i3c_master_cleanup(struct i3c_master_controller *master)
> > > > > >  EXPORT_SYMBOL_GPL(i3c_master_cleanup);
> > > > > >  
> > > > > >  /**
> > > > > > + * i3c_secondary_master_register() - register an secondary I3C master
> > > > > > + * @master: master used to send frames on the bus
> > > > > > + * @info: master info, describes this device
> > > > > > + *
> > > > > > + * This function takes care of everything for you:
> > > > > > + *
> > > > > > + * - updates this master info
> > > > > > + * - registers the I2C adapter
> > > > > > + * - if possible, populates the bus with devices received by DEFSLVS
> > > > > > + *   command
> > > > > > + *
> > > > > > + * Return: 0 in case of success, a negative error code otherwise.
> > > > > > + */
> > > > > > +int i3c_secondary_master_register(struct i3c_master_controller *master,
> > > > > > +				  struct i3c_device_info *info)
> > > > > > +{
> > > > > > +	int ret;
> > > > > > +
> > > > > > +	ret = i3c_master_set_info(master, info, master->secondary);
> > > > > > +	if (ret)
> > > > > > +		return ret;
> > > > > > +
> > > > > > +	ret = master->ops->bus_init(master);
> > > > > > +	if (ret)
> > > > > > +		return ret;  
> > > > > 
> > > > > At this point you don't have enough information to do the bus 
> > > > > initialization.
> > > > >   
> > > > 
> > > > Actually, current ->bus_init() implementations (in CDNS and DW) does not
> > > > initialize the bus. We are just setting the mode, configuring some init values
> > > > in the registers and enabling the core. Maybe we should rename it?  
> > > 
> > > The name for me its ok. My point was that when you call 
> > > i3c_secondary_master_register() in CDNS you don't have yet DEFSLVS 
> > > information.  
> > 
> > It depends. When current master did not initialize the bus yet, this is true.
> > But when master and the bus are already initialized, I have DEFSLVS. Different
> > story is that devices aren't added to the subsystem yet. So what I have do in
> > that case is to enable to let HC operate and populate the bus later (using  
> > ->populate_bus() hook)  
> 
> Ahh I didn't see, you are calling it in two different places. Does it 
> make sense?
> 
> It is more logical to do the secondary_master_register() after get the 
> bus ownership (just need the first time), otherwise the HC is just a 
> slave.

I think we've tried that approach, and I wasn't happy with the end
result. Don't remember the exact reason, but it was something related
to extra complexity related to init/registration steps in HC drivers.
You can look at my previous reviews if you want more details.

> > > > > 
> > > > > In generally I found this intrusive for the current eco system.
> > > > > 
> > > > > I propose the following:
> > > > > 1 - Keep the function i3c_master_register() as is and go out before   
> > > > 
> > > > We had that version previously. We decided to split it.  
> > > 
> > > You just need to split the secondary master part from it. So you can go 
> > > out before i3c_master_bus_init() and keep the same function.  
> > 
> > We discussed that with Boris and we decided to split this function in this
> > version to make things clear.  
> 
> My proposal isn't to much different with the advantage that it not broke 
> the existing code.

How do we break existing code? Can you please be more specific when you
make such statements so we can fix the problems. And no, keeping kernel
APIs/interfaces stable has never been our goal. Actually, it's quite the
opposite: the I3C subsystem is new, and if we see some of the initial
functions/interfaces/hooks do not apply well to some of the new
features we want to support, we should fix them, instead of trying to
workaround them.

> 
> >   
> > > 
> > > Them use i3c_secondary_master_register() when received DEFSLVS or ENEC 
> > > MR.  
> > 
> > It is also possible that our controller received DA and DEFSLVS even before
> > master registration. We should try to register that, this is something I'm
> > testing in my scenarios.  
> 
> That shouldn't be a problem. You receive DA and them DEFSLVS.
> 
> Add DEFSLVS to the system and try to be current master.
> 
> If you get the ownership, do:
> 	i3c_secondary_master_register()
> 	retrieve defslvs info and add them to the system.

That's not so simple. You have cases where the DEFLSLVS CCC has been
received before the driver was loaded. In that case you should call
i3c_secondary_master_register() in the probe path. It's this extra
complexity about when to call i3c_secondary_master_register() (and
other init steps related to that) that I was complaining about with
this approach.

> 
> After this you will see everything in /sys/bus/i3c/devices
> 
> If you don't get the ownership, it is ok because HC is just a slave.
> 
> I would try to da all management task in subsystem.

Again, please be more specific in your proposals. It's easy to come up
with some high-level suggestions like "you should be able to do it this
way", but unless you've actually tried you can't tell if that's possible
or cleaner. I wish you had taken part to the discussion when it started
and had followed the evolution of the patch series, this way you'd
realized that we tried some of the things you suggest here and decided
to do it differently because the end result was not so great.

Regards,

Boris

_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem
  2019-08-11 10:17             ` Boris Brezillon
@ 2019-08-12 13:55               ` Vitor Soares
  2019-08-12 14:55                 ` Boris Brezillon
  0 siblings, 1 reply; 21+ messages in thread
From: Vitor Soares @ 2019-08-12 13:55 UTC (permalink / raw)
  To: Boris Brezillon, Vitor Soares, Przemyslaw Gaj
  Cc: linux-i3c, agolec, rafalc, bbrezillon

Hi Boris,

From: Boris Brezillon <boris.brezillon@collabora.com>
Date: Sun, Aug 11, 2019 at 11:17:38

> Hi Przemek, Vitor,
> 
> Sorry for the late reply.
> 
> On Fri, 12 Jul 2019 11:28:36 +0000
> Vitor Soares <Vitor.Soares@synopsys.com> wrote:
> 
> > > > > > > ---
> > > > > > > 
> > > > > > > Main changes between v4 and v5:
> > > > > > > - Add function to test if master owns the bus
> > > > > > > - Add i3c_secondary_master_register() function
> > > > > > > - Add populate_bus() hook to populate the bus after mastership takeover  
> > > > > > 
> > > > > > For me this task is for the sub-system not the host controller.
> > > > > >   
> > > > > 
> > > > > I'm not sure where device information is stored in DW controller but in CDNS
> > > > > controller DEFSLVS frame is processed in the device and the only thing I got is
> > > > > information that DEFSLVS came in.   
> > > > 
> > > > When you receive this notification you can add the device to subsystem to 
> > > > be initialized later when get bus ownership.  
> > > 
> > > I added this hook mostly because we have to lock the bus during devices
> > > addition. If we pass DEFSLVS devices information to the system in some
> > > structure, we should be ok. We can lock the bus in the framework and register
> > > all the devices. But I still don't feel this is good solution, I'll have to
> > > do the job once again which HW did before  
> > 
> > Your HW just fill a table with the DEFSLVS data and you still have to 
> > access, retrieve the information and attached to the controller (same 
> > approach as DAA).
> > 
> > If all these management is passed to the subsystem it will be more easy 
> > to maintain and HC agonistic.
> > 
> > > 
> > > @Boris, what do you think about that?
> 
> If there's nothing HW specific in ->populate_bus(), then yes, it makes
> sense to have it done in the core based on information extracted from
> the DEFSLVS frame.
> 
> > >   
> > > >   
> > > > > I need to inform subsystem that there are new
> > > > > device (if any).
> > > > > I remember we talkad about that already, you have access to
> > > > > DEFSLVS information directly, correct?  
> > > > 
> > > > I can process it in the HC driver, but my point is that I want to rely it 
> > > > to the subsystem the bus population with the function already present.
> > > >   
> > > 
> > > So, do you want to pack those informations back to i3c_ccc_defslvs and pass to
> > > the subsystem?  
> > 
> > Not necessary. It can be passed addr, bcr, dcr and lvr. 
> > 
> > In the subsystem I think it should be a list of i3c_ccc_defslvs that 
> > holds DEFSLVS information.
> 
> Sorry, I don't get what you mean here. Why would we want a list of
> i3c_ccc_defslvs objects when i3c_ccc_defslvs already stores an
> array of devices. I guess you meant a list of struct i3c_ccc_dev_desc
> objects.

I'm using a list with i3c_ccc_dev_desc objects to hold the DEFSLVS. When 
secondary master to get the bus ownership I initialize those devices and 
after I clean the list.
IMO we should avoid initializing devices when having device drivers 
trying to talk with the bus.

> 
> > 
> > >   
> > > > >   
> > > > > > > - Rework device information retrieval to allow adding partialy discovered
> > > > > > > devices
> > > > > > > 
> > > > > > > Main changes between v3 and v4:
> > > > > > > - Add i3c_master_acquire_bus_ownership to acquire the bus
> > > > > > > - Refactored the code
> > > > > > > 
> > > > > > > Main changes between v2 and v3:
> > > > > > > - Add i3c_bus_downgrade_maintenance_lock() for downgrading the bus
> > > > > > > lock from maintenance to normal use
> > > > > > > - Add additional fields to i2c_dev_desc for DEFSLVS purpose (addr, lvr)
> > > > > > > - Add i3c_master_register_new_i2c_devs() function to register I2C devices
> > > > > > > - Reworked I2C devices registration on secondary master side
> > > > > > > 
> > > > > > > Changes in v2:
> > > > > > > - Add mastership disable event hook
> > > > > > > - Changed name of mastership enable event hook
> > > > > > > - Add function to test if master owns the bus
> > > > > > > - Removed op_mode
> > > > > > > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > > > > > > pass full i3c_device_info
> > > > > > > - Changed name of mastership enable event hook
> > > > > > > - Add function to test if master owns the bus
> > > > > > > - Removed op_mode
> > > > > > > - Changed parameter of i3c_master_get_accmst_locked, no need to
> > > > > > > pass full i3c_device_info
> > > > > > > - Removed redundant DEFSLVS command before GETACCMST
> > > > > > > - Add i3c_master_bus_takeover function. There is a need to lock
> > > > > > > the bus before adding devices and no matter of the controller
> > > > > > > devices have to be added after mastership takeover.
> > > > > > > - Add device registration during initialization on secondary master
> > > > > > > side. Devices received by DEFSLVS (if occured). If not, device
> > > > > > > initialization is deffered untill next mastership request.
> > > > > > > ---
> > > > > > >  drivers/i3c/device.c       |  26 ++
> > > > > > >  drivers/i3c/internals.h    |   4 +
> > > > > > >  drivers/i3c/master.c       | 588 ++++++++++++++++++++++++++++++++++++++-------
> > > > > > >  include/linux/i3c/master.h |  34 ++-
> > > > > > >  4 files changed, 563 insertions(+), 89 deletions(-)
> > > > > > > 
> > > > > > > diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
> > > > > > > index 69cc040..b60f637 100644
> > > > > > > --- a/drivers/i3c/device.c
> > > > > > > +++ b/drivers/i3c/device.c
> > > > > > > @@ -43,7 +43,13 @@ int i3c_device_do_priv_xfers(struct i3c_device *dev,
> > > > > > >  	}
> > > > > > >  
> > > > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > > > +	if (ret)
> > > > > > > +		goto err_unlock_bus;
> > > > > > > +
> > > > > > >  	ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
> > > > > > > +
> > > > > > > +err_unlock_bus:
> > > > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > > > >  
> > > > > > >  	return ret;
> > > > > > > @@ -114,11 +120,17 @@ int i3c_device_enable_ibi(struct i3c_device *dev)
> > > > > > >  	int ret = -ENOENT;
> > > > > > >  
> > > > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > > > +	if (ret)
> > > > > > > +		goto err_unlock_bus;
> > > > > > > +
> > > > > > >  	if (dev->desc) {
> > > > > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > > > > >  		ret = i3c_dev_enable_ibi_locked(dev->desc);
> > > > > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > > > > >  	}
> > > > > > > +
> > > > > > > +err_unlock_bus:
> > > > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > > > >  
> > > > > > >  	return ret;
> > > > > > > @@ -145,11 +157,17 @@ int i3c_device_request_ibi(struct i3c_device *dev,
> > > > > > >  		return -EINVAL;
> > > > > > >  
> > > > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > > > +	if (ret)
> > > > > > > +		goto err_unlock_bus;
> > > > > > > +
> > > > > > >  	if (dev->desc) {
> > > > > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > > > > >  		ret = i3c_dev_request_ibi_locked(dev->desc, req);
> > > > > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > > > > >  	}
> > > > > > > +
> > > > > > > +err_unlock_bus:
> > > > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > > > >  
> > > > > > >  	return ret;
> > > > > > > @@ -166,12 +184,20 @@ EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
> > > > > > >   */
> > > > > > >  void i3c_device_free_ibi(struct i3c_device *dev)
> > > > > > >  {
> > > > > > > +	int ret;
> > > > > > > +
> > > > > > >  	i3c_bus_normaluse_lock(dev->bus);
> > > > > > > +	ret = i3c_master_acquire_bus_ownership(dev->desc->common.master);
> > > > > > > +	if (ret)
> > > > > > > +		goto err_unlock_bus;
> > > > > > > +
> > > > > > >  	if (dev->desc) {
> > > > > > >  		mutex_lock(&dev->desc->ibi_lock);
> > > > > > >  		i3c_dev_free_ibi_locked(dev->desc);
> > > > > > >  		mutex_unlock(&dev->desc->ibi_lock);
> > > > > > >  	}
> > > > > > > +
> > > > > > > +err_unlock_bus:
> > > > > > >  	i3c_bus_normaluse_unlock(dev->bus);
> > > > > > >  }
> > > > > > >  EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
> > > > > > > diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
> > > > > > > index 86b7b44..cdfc5bf 100644
> > > > > > > --- a/drivers/i3c/internals.h
> > > > > > > +++ b/drivers/i3c/internals.h
> > > > > > > @@ -14,6 +14,10 @@ extern struct bus_type i3c_bus_type;
> > > > > > >  
> > > > > > >  void i3c_bus_normaluse_lock(struct i3c_bus *bus);
> > > > > > >  void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
> > > > > > > +void i3c_bus_maintenance_lock(struct i3c_bus *bus);
> > > > > > > +void i3c_bus_maintenance_unlock(struct i3c_bus *bus);  
> > > > > > 
> > > > > > These function are static.
> > > > > >   
> > > > > 
> > > > > I forgot to revert that change to previous state.
> > > > >   
> > > > > > > +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master);
> > > > > > > +  
> > > > > > 
> > > > > > What do you think to pass this logic to master.c?
> > > > > >   
> > > > > 
> > > > > Isn't it there?  
> > > > 
> > > > I meant make it static and remove its call from device.c.
> 
> Can you be more specific? Where would you move the
> i3c_master_acquire_bus_ownership() call? Note that we already
> considered different options and the solution proposed here was the
> cleanest race-free one.

Did you consider to pass it to i3c_dev_do_priv_xfers_locked()?
Can you help me to understand the drawbacks?

> 
> > > >   
> > > > >   
> > > > > > >  
> > > > > > >  int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
> > > > > > >  				 struct i3c_priv_xfer *xfers,
> > > > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> > > > > > > index cbace14..3b44e66 100644
> > > > > > > --- a/drivers/i3c/master.c
> > > > > > > +++ b/drivers/i3c/master.c
> > > > > > > @@ -93,6 +93,18 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
> > > > > > >  	up_read(&bus->lock);
> > > > > > >  }
> > > > > > >  
> > > > > > > +/*
> > > > > > > + * i3c_bus_downgrade_maintenance_lock - Downgrade the bus lock to normal
> > > > > > > + * operation
> > > > > > > + *
> > > > > > > + * Should be called when a maintenance operation is done and normal
> > > > > > > + * operation is planned. See i3c_bus_maintenance_lock() and
> > > > > > > + * i3c_bus_normaluse_lock() for more details.
> > > > > > > + */
> > > > > > > +static void i3c_bus_downgrade_maintenance_lock(struct i3c_bus *bus)
> > > > > > > +{
> > > > > > > +	downgrade_write(&bus->lock);
> > > > > > > +}
> > > > > > >  static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
> > > > > > >  {
> > > > > > >  	return container_of(dev, struct i3c_master_controller, dev);
> > > > > > > @@ -341,6 +353,22 @@ static int i3c_device_probe(struct device *dev)
> > > > > > >  	return driver->probe(i3cdev);
> > > > > > >  }
> > > > > > >  
> > > > > > > +static int
> > > > > > > +i3c_master_enable_mr_events_locked(struct i3c_master_controller *master)
> > > > > > > +{
> > > > > > > +	if (!master->ops->enable_mr_events)
> > > > > > > +		return -ENOTSUPP;
> > > > > > > +
> > > > > > > +	return master->ops->enable_mr_events(master);
> > > > > > > +}
> > > > > > > +
> > > > > > > +static void i3c_master_disable_mr_events(struct i3c_master_controller *master)
> > > > > > > +{
> > > > > > > +	if (!master->ops->disable_mr_events)
> > > > > > > +		return;
> > > > > > > +
> > > > > > > +	master->ops->disable_mr_events(master);
> > > > > > > +}  
> > > > > > 
> > > > > > Add new line.
> > > > > > 
> > > > > > It is not clear to me what you expect with these functions. Do you want 
> > > > > > to enable MR from all devices? Just some of them? How do you decide which 
> > > > > > secondary masters are allow earn the bus ownership?
> > > > > >   
> > > > > 
> > > > > We discussed this also. For now, we enable ENEC for all masters on the bus, we
> > > > > can change it later if needed.   
> > > > 
> > > > I would say to expand the current ibi framework to accommodate MR and  
> > > 
> > > Can you tell something more here? What benefits you see  
> > 
> > Just starting with the name. IBI stands for In Band Interrupt which can 
> > be MR, HJ or SIR.
> > 
> > Also the concept is the same, let say you are registering a SIR w/out 
> > data but in fact it is a MR.
> 
> No, it's not from a SW PoV. IBI are events I3C device drivers can
> register a handler for, MR and HJ events are things the HC drivers are
> expected to handle, and that's a big difference. While re-using the IBI
> API to handle them should be doable I don't think it will make things
> simpler.
> 

In that case we need to rename the functions with slave interrupt request 
(SIR) in mind.

> > 
> > >   
> > > > also add platform entry to allow secondary masters on the bus.  
> > > 
> > > This is something we can consider, to select devices which can request
> > > mastership. But I don't see the problem adding that later also.  
> > 
> 
> Fully agree with that, that's still something we can consider
> restricting afterwards. Remember that I3C is still not widely deployed
> and we only have 2 controller drivers so far, so patching them should be
> fairly easy if we decide to change the interface.

I think is too premature have a secondary master implementation. For now, 
I would say this is only good for testing purposes.


> 
> > 
> > 
> > >   
> > > >   
> > > > > Also, priority level is encoded in slave address
> > > > > so current master will give the control to the master with lower address first.
> > > > > It shouldn't be a problem.  
> > > > 
> > > > You can have security issues and the devices on the bus might not be 
> > > > prepared to work in multi-master environment.  
> > > 
> > > I don't get it, can you explan what do you mean? Which devices might not be
> > > prapared to work in multi-master environment, slaves? Key feature of I3C is
> > > multi-master capability. Mastership request should also be transparent for pure
> > > slaves on the bus. Of course, secondary masters should work in multi-master
> > > configuration  
> > 
> > So you are probing the same hw device on two different systems. This mean 
> > that in system A you can have the configuration A and in system B the 
> > configuration B.
> > How will you deal with this?
> 
> That's certainly something we should take care of, by restoring
> previous device configs every time a bus handover happens. It will
> probably involve some kind of collaboration between the core and device
> drivers, because part of the configuration (everything that's set
> through private SDR transfers) is only known by device users. The core
> can take care of restoring IBIs config though.
> 
> 
> > > > > > > +/**
> > > > > > > + * i3c_master_bus_takeover() - register new I3C devices on bus takeover
> > > > > > > + * @master: master used to send frames on the bus
> > > > > > > + *
> > > > > > > + * This function is useful when devices were not added
> > > > > > > + * during initialization or when new device joined the bus
> > > > > > > + * which wasn't under our control.
> > > > > > > + */
> > > > > > > +void i3c_master_bus_takeover(struct i3c_master_controller *master)
> > > > > > > +{
> > > > > > > +	struct i3c_dev_desc *i3cdev, *i3ctmp;
> > > > > > > +	int ret;
> > > > > > > +
> > > > > > > +	master->want_to_acquire_bus = false;  
> > > > > > 
> > > > > > Can you explain the usage of this variable?
> > > > > >   
> > > > > 
> > > > > The idea of this was to let HC know that we want to acquire the bus after
> > > > > ENEC(MR) received in slave mode.  
> > > > 
> > > > With the logic that I proposed you don't need this. When received ENEC 
> > > > you will try to get the bus ownership if HC not fully initialized or have 
> > > > DEFSLVS to add, otherwise you don't need to get the bus ownership.  
> > > 
> > > In case devices on the bus are the same, I agree. But please consider the case
> > > when slave joins the bus (Hot-Join) and MR event is disabled for now, our
> > > secondary master receives DEFSLVS, we add that device to the subsystem but
> > > cannot request mastership yet. We need a flag to indicate that we should
> > > request mastership on next ENEC(MR). It doesn't make sense to request
> > > mastership every time when ENEC(MR) is received.  
> > 
> > At least I think you can give a mean for the flag name, otherwise it is 
> > not clear why sec master want bus ownership.
> 
> Well, I guess the idea was to use the same flag for any kind of
> deferred MR requests. Not sure the reason for this MR request is really
> important since the same set of actions will be done anyway. Do you have
> a use case where we need to know the reason of a MR? If that's the
> case, or if we want to know it for debug purpose, I'd recommend adding
> extra flags to express that while keeping the want_to_acquire_bus one.

In my case, I don't need such a flag.
For now, I do MR when having Sec. Master to initialize, DEFSLVS to add or 
clients wanting transfer data.

> 
> > 
> > >   
> > > >   
> > > > >   
> > > > > > > +
> > > > > > > +	if (!master->init_done)
> > > > > > > +		return;
> > > > > > > +
> > > > > > > +	i3c_bus_maintenance_lock(&master->bus);
> > > > > > > +	master->ops->populate_bus(master);
> > > > > > > +
> > > > > > > +	list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c,
> > > > > > > +				 common.node) {
> > > > > > > +		if (i3cdev->info.pid)
> > > > > > > +			continue;
> > > > > > > +
> > > > > > > +		ret = i3c_master_retrieve_info_and_reuse(master, i3cdev);
> > > > > > > +		if (ret) {
> > > > > > > +			if (i3cdev->dev && i3cdev->dev->desc)
> > > > > > > +				i3cdev->dev->desc = NULL;
> > > > > > > +
> > > > > > > +			i3c_master_detach_i3c_dev(i3cdev);
> > > > > > > +		}
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * If current master finished bus initialization properly, we can
> > > > > > > +	 * enable Mastership event.
> > > > > > > +	 */
> > > > > > > +	ret = i3c_master_enable_mr_events_locked(master);
> > > > > > > +	if (ret)
> > > > > > > +		dev_warn(&master->dev, "ENEC(MR) failed (ret = %i)", ret);
> > > > > > > +
> > > > > > > +	i3c_bus_maintenance_unlock(&master->bus);
> > > > > > > +
> > > > > > > +	i3c_master_register_new_devs(master);
> > > > > > > +}
> > > > > > > +EXPORT_SYMBOL_GPL(i3c_master_bus_takeover);
> > > > > > > +
> > > > > > >  /**
> > > > > > >   * i3c_master_init() - initializes all the structures required by I3C master
> > > > > > >   * @master: master used to send frames on the bus
> > > > > > > @@ -2417,9 +2712,6 @@ int i3c_master_init(struct i3c_master_controller *master,
> > > > > > >  	struct i2c_dev_boardinfo *i2cbi;
> > > > > > >  	int ret;
> > > > > > >  
> > > > > > > -	/* We do not support secondary masters yet. */
> > > > > > > -	if (secondary)
> > > > > > > -		return -ENOTSUPP;
> > > > > > >  
> > > > > > >  	ret = i3c_master_check_ops(ops);
> > > > > > >  	if (ret)
> > > > > > > @@ -2432,6 +2724,7 @@ int i3c_master_init(struct i3c_master_controller *master,
> > > > > > >  	master->dev.release = i3c_masterdev_release;
> > > > > > >  	master->ops = ops;
> > > > > > >  	master->secondary = secondary;
> > > > > > > +	master->want_to_acquire_bus = secondary;
> > > > > > >  	INIT_LIST_HEAD(&master->boardinfo.i2c);
> > > > > > >  	INIT_LIST_HEAD(&master->boardinfo.i3c);
> > > > > > >  
> > > > > > > @@ -2488,6 +2781,92 @@ void i3c_master_cleanup(struct i3c_master_controller *master)
> > > > > > >  EXPORT_SYMBOL_GPL(i3c_master_cleanup);
> > > > > > >  
> > > > > > >  /**
> > > > > > > + * i3c_secondary_master_register() - register an secondary I3C master
> > > > > > > + * @master: master used to send frames on the bus
> > > > > > > + * @info: master info, describes this device
> > > > > > > + *
> > > > > > > + * This function takes care of everything for you:
> > > > > > > + *
> > > > > > > + * - updates this master info
> > > > > > > + * - registers the I2C adapter
> > > > > > > + * - if possible, populates the bus with devices received by DEFSLVS
> > > > > > > + *   command
> > > > > > > + *
> > > > > > > + * Return: 0 in case of success, a negative error code otherwise.
> > > > > > > + */
> > > > > > > +int i3c_secondary_master_register(struct i3c_master_controller *master,
> > > > > > > +				  struct i3c_device_info *info)
> > > > > > > +{
> > > > > > > +	int ret;
> > > > > > > +
> > > > > > > +	ret = i3c_master_set_info(master, info, master->secondary);
> > > > > > > +	if (ret)
> > > > > > > +		return ret;
> > > > > > > +
> > > > > > > +	ret = master->ops->bus_init(master);
> > > > > > > +	if (ret)
> > > > > > > +		return ret;  
> > > > > > 
> > > > > > At this point you don't have enough information to do the bus 
> > > > > > initialization.
> > > > > >   
> > > > > 
> > > > > Actually, current ->bus_init() implementations (in CDNS and DW) does not
> > > > > initialize the bus. We are just setting the mode, configuring some init values
> > > > > in the registers and enabling the core. Maybe we should rename it?  
> > > > 
> > > > The name for me its ok. My point was that when you call 
> > > > i3c_secondary_master_register() in CDNS you don't have yet DEFSLVS 
> > > > information.  
> > > 
> > > It depends. When current master did not initialize the bus yet, this is true.
> > > But when master and the bus are already initialized, I have DEFSLVS. Different
> > > story is that devices aren't added to the subsystem yet. So what I have do in
> > > that case is to enable to let HC operate and populate the bus later (using  
> > > ->populate_bus() hook)  
> > 
> > Ahh I didn't see, you are calling it in two different places. Does it 
> > make sense?
> > 
> > It is more logical to do the secondary_master_register() after get the 
> > bus ownership (just need the first time), otherwise the HC is just a 
> > slave.
> 
> I think we've tried that approach, and I wasn't happy with the end
> result. Don't remember the exact reason, but it was something related
> to extra complexity related to init/registration steps in HC drivers.
> You can look at my previous reviews if you want more details.

I tested both cases and doing secondary_master_register() after get the 
bus ownership I was able to reuse more code.

> 
> > > > > > 
> > > > > > In generally I found this intrusive for the current eco system.
> > > > > > 
> > > > > > I propose the following:
> > > > > > 1 - Keep the function i3c_master_register() as is and go out before   
> > > > > 
> > > > > We had that version previously. We decided to split it.  
> > > > 
> > > > You just need to split the secondary master part from it. So you can go 
> > > > out before i3c_master_bus_init() and keep the same function.  
> > > 
> > > We discussed that with Boris and we decided to split this function in this
> > > version to make things clear.  
> > 
> > My proposal isn't to much different with the advantage that it not broke 
> > the existing code.
> 
> How do we break existing code? Can you please be more specific when you
> make such statements so we can fix the problems. And no, keeping kernel
> APIs/interfaces stable has never been our goal. Actually, it's quite the
> opposite: the I3C subsystem is new, and if we see some of the initial
> functions/interfaces/hooks do not apply well to some of the new
> features we want to support, we should fix them, instead of trying to
> workaround them.

I wasn't able to apply the patch directly and I based my comments on the 
tests that I made.
During the process I didn't feel the need to work around anything (on 
current API) to implement secondary master.

> 
> > 
> > >   
> > > > 
> > > > Them use i3c_secondary_master_register() when received DEFSLVS or ENEC 
> > > > MR.  
> > > 
> > > It is also possible that our controller received DA and DEFSLVS even before
> > > master registration. We should try to register that, this is something I'm
> > > testing in my scenarios.  
> > 
> > That shouldn't be a problem. You receive DA and them DEFSLVS.
> > 
> > Add DEFSLVS to the system and try to be current master.
> > 
> > If you get the ownership, do:
> > 	i3c_secondary_master_register()
> > 	retrieve defslvs info and add them to the system.
> 
> That's not so simple. You have cases where the DEFLSLVS CCC has been
> received before the driver was loaded. In that case you should call
> i3c_secondary_master_register() in the probe path. 

You don't need that. Just try to became the master, if not, wait for ENEC 
MR.
The process is the same in both cases.

> It's this extra
> complexity about when to call i3c_secondary_master_register() (and
> other init steps related to that) that I was complaining about with
> this approach.
> 
> > 
> > After this you will see everything in /sys/bus/i3c/devices
> > 
> > If you don't get the ownership, it is ok because HC is just a slave.
> > 
> > I would try to da all management task in subsystem.
> 
> Again, please be more specific in your proposals. It's easy to come up
> with some high-level suggestions like "you should be able to do it this
> way", but unless you've actually tried you can't tell if that's possible
> or cleaner. I wish you had taken part to the discussion when it started
> and had followed the evolution of the patch series, this way you'd
> realized that we tried some of the things you suggest here and decided
> to do it differently because the end result was not so great.
> 
> Regards,
> 
> Boris

The secondary master is probably the most advanced feature in I3C and 
since beginning I'm complaining that it just fit your use case.
Even now, I don't see clear how to fit slave API in this use case.
In beginning when we started this secondary master topic, I pointed out 
the i2c multi master approach and you the OTG from USB. So far I don't 
see neither approach being used and we trying to reinvent the wheel.

Anyway I will try to come-up with a RFC based on what you are currently 
working yet it is only for testing.
Maybe we can split secondary master feature in phases:
  - Sec Master initialization
  - Mastership request
  - Mastership deliver
  - Mastership handoff
  - Mastership takeover 
  - Register DEFSLVS
  - Restore SIR request from slaves
  - Handle I3C device driver clients transfers on sec master side

It will be easier to follow the patches.

Best regards,
Vitor Soares

_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem
  2019-08-12 13:55               ` Vitor Soares
@ 2019-08-12 14:55                 ` Boris Brezillon
  2019-08-22 11:08                   ` Vitor Soares
  0 siblings, 1 reply; 21+ messages in thread
From: Boris Brezillon @ 2019-08-12 14:55 UTC (permalink / raw)
  To: Vitor Soares; +Cc: Przemyslaw Gaj, agolec, linux-i3c, rafalc, bbrezillon

Hi Vitor,

On Mon, 12 Aug 2019 13:55:34 +0000
Vitor Soares <Vitor.Soares@synopsys.com> wrote:

> > > > > > I need to inform subsystem that there are new
> > > > > > device (if any).
> > > > > > I remember we talkad about that already, you have access to
> > > > > > DEFSLVS information directly, correct?    
> > > > > 
> > > > > I can process it in the HC driver, but my point is that I want to rely it 
> > > > > to the subsystem the bus population with the function already present.
> > > > >     
> > > > 
> > > > So, do you want to pack those informations back to i3c_ccc_defslvs and pass to
> > > > the subsystem?    
> > > 
> > > Not necessary. It can be passed addr, bcr, dcr and lvr. 
> > > 
> > > In the subsystem I think it should be a list of i3c_ccc_defslvs that 
> > > holds DEFSLVS information.  
> > 
> > Sorry, I don't get what you mean here. Why would we want a list of
> > i3c_ccc_defslvs objects when i3c_ccc_defslvs already stores an
> > array of devices. I guess you meant a list of struct i3c_ccc_dev_desc
> > objects.  
> 
> I'm using a list with i3c_ccc_dev_desc objects to hold the DEFSLVS. When 
> secondary master to get the bus ownership I initialize those devices and 
> after I clean the list.

Okay, sounds reasonable.

> IMO we should avoid initializing devices when having device drivers 
> trying to talk with the bus.

This initialization has to happen at some point, even if drivers keep
doing transfers on the bus, but I guess we can try delaying that a bit
until all already queued transfers have been issued.

> > > > > > > > +int i3c_master_acquire_bus_ownership(struct i3c_master_controller *master);
> > > > > > > > +    
> > > > > > > 
> > > > > > > What do you think to pass this logic to master.c?
> > > > > > >     
> > > > > > 
> > > > > > Isn't it there?    
> > > > > 
> > > > > I meant make it static and remove its call from device.c.  
> > 
> > Can you be more specific? Where would you move the
> > i3c_master_acquire_bus_ownership() call? Note that we already
> > considered different options and the solution proposed here was the
> > cleanest race-free one.  
> 
> Did you consider to pass it to i3c_dev_do_priv_xfers_locked()?

Yes.

> Can you help me to understand the drawbacks?

Because then this function can't be used from inside the framework,
when the master already owns the bus. For i3c_dev_do_priv_xfers_locked()
that's not a problem, because we shouldn't use it inside master.c, but
that's an issue for IBI related functions
(i3c_dev_{enable,request,free}_ibi_locked()).


> > > > > > > 
> > > > > > > It is not clear to me what you expect with these functions. Do you want 
> > > > > > > to enable MR from all devices? Just some of them? How do you decide which 
> > > > > > > secondary masters are allow earn the bus ownership?
> > > > > > >     
> > > > > > 
> > > > > > We discussed this also. For now, we enable ENEC for all masters on the bus, we
> > > > > > can change it later if needed.     
> > > > > 
> > > > > I would say to expand the current ibi framework to accommodate MR and    
> > > > 
> > > > Can you tell something more here? What benefits you see    
> > > 
> > > Just starting with the name. IBI stands for In Band Interrupt which can 
> > > be MR, HJ or SIR.
> > > 
> > > Also the concept is the same, let say you are registering a SIR w/out 
> > > data but in fact it is a MR.  
> > 
> > No, it's not from a SW PoV. IBI are events I3C device drivers can
> > register a handler for, MR and HJ events are things the HC drivers are
> > expected to handle, and that's a big difference. While re-using the IBI
> > API to handle them should be doable I don't think it will make things
> > simpler.
> >   
> 
> In that case we need to rename the functions with slave interrupt request 
> (SIR) in mind.

I'm fine changing ibi for sir. Can you send a patch doing that?

> 
> > >   
> > > >     
> > > > > also add platform entry to allow secondary masters on the bus.    
> > > > 
> > > > This is something we can consider, to select devices which can request
> > > > mastership. But I don't see the problem adding that later also.    
> > >   
> > 
> > Fully agree with that, that's still something we can consider
> > restricting afterwards. Remember that I3C is still not widely deployed
> > and we only have 2 controller drivers so far, so patching them should be
> > fairly easy if we decide to change the interface.  
> 
> I think is too premature have a secondary master implementation. For now, 
> I would say this is only good for testing purposes.

I don't think that's a problem, as long as we're not afraid of changing
things afterward. Keeping this implementation out-of-tree does not help
either since it forces potential users to apply the patches (or even
worse, re-implement the whole thing if they don't notice people have
already worked on the feature).


> > > > > > > > +/**
> > > > > > > > + * i3c_master_bus_takeover() - register new I3C devices on bus takeover
> > > > > > > > + * @master: master used to send frames on the bus
> > > > > > > > + *
> > > > > > > > + * This function is useful when devices were not added
> > > > > > > > + * during initialization or when new device joined the bus
> > > > > > > > + * which wasn't under our control.
> > > > > > > > + */
> > > > > > > > +void i3c_master_bus_takeover(struct i3c_master_controller *master)
> > > > > > > > +{
> > > > > > > > +	struct i3c_dev_desc *i3cdev, *i3ctmp;
> > > > > > > > +	int ret;
> > > > > > > > +
> > > > > > > > +	master->want_to_acquire_bus = false;    
> > > > > > > 
> > > > > > > Can you explain the usage of this variable?
> > > > > > >     
> > > > > > 
> > > > > > The idea of this was to let HC know that we want to acquire the bus after
> > > > > > ENEC(MR) received in slave mode.    
> > > > > 
> > > > > With the logic that I proposed you don't need this. When received ENEC 
> > > > > you will try to get the bus ownership if HC not fully initialized or have 
> > > > > DEFSLVS to add, otherwise you don't need to get the bus ownership.    
> > > > 
> > > > In case devices on the bus are the same, I agree. But please consider the case
> > > > when slave joins the bus (Hot-Join) and MR event is disabled for now, our
> > > > secondary master receives DEFSLVS, we add that device to the subsystem but
> > > > cannot request mastership yet. We need a flag to indicate that we should
> > > > request mastership on next ENEC(MR). It doesn't make sense to request
> > > > mastership every time when ENEC(MR) is received.    
> > > 
> > > At least I think you can give a mean for the flag name, otherwise it is 
> > > not clear why sec master want bus ownership.  
> > 
> > Well, I guess the idea was to use the same flag for any kind of
> > deferred MR requests. Not sure the reason for this MR request is really
> > important since the same set of actions will be done anyway. Do you have
> > a use case where we need to know the reason of a MR? If that's the
> > case, or if we want to know it for debug purpose, I'd recommend adding
> > extra flags to express that while keeping the want_to_acquire_bus one.  
> 
> In my case, I don't need such a flag.
> For now, I do MR when having Sec. Master to initialize, DEFSLVS to add or 
> clients wanting transfer data.

Okay.


> > > > > > > >  /**
> > > > > > > > + * i3c_secondary_master_register() - register an secondary I3C master
> > > > > > > > + * @master: master used to send frames on the bus
> > > > > > > > + * @info: master info, describes this device
> > > > > > > > + *
> > > > > > > > + * This function takes care of everything for you:
> > > > > > > > + *
> > > > > > > > + * - updates this master info
> > > > > > > > + * - registers the I2C adapter
> > > > > > > > + * - if possible, populates the bus with devices received by DEFSLVS
> > > > > > > > + *   command
> > > > > > > > + *
> > > > > > > > + * Return: 0 in case of success, a negative error code otherwise.
> > > > > > > > + */
> > > > > > > > +int i3c_secondary_master_register(struct i3c_master_controller *master,
> > > > > > > > +				  struct i3c_device_info *info)
> > > > > > > > +{
> > > > > > > > +	int ret;
> > > > > > > > +
> > > > > > > > +	ret = i3c_master_set_info(master, info, master->secondary);
> > > > > > > > +	if (ret)
> > > > > > > > +		return ret;
> > > > > > > > +
> > > > > > > > +	ret = master->ops->bus_init(master);
> > > > > > > > +	if (ret)
> > > > > > > > +		return ret;    
> > > > > > > 
> > > > > > > At this point you don't have enough information to do the bus 
> > > > > > > initialization.
> > > > > > >     
> > > > > > 
> > > > > > Actually, current ->bus_init() implementations (in CDNS and DW) does not
> > > > > > initialize the bus. We are just setting the mode, configuring some init values
> > > > > > in the registers and enabling the core. Maybe we should rename it?    
> > > > > 
> > > > > The name for me its ok. My point was that when you call 
> > > > > i3c_secondary_master_register() in CDNS you don't have yet DEFSLVS 
> > > > > information.    
> > > > 
> > > > It depends. When current master did not initialize the bus yet, this is true.
> > > > But when master and the bus are already initialized, I have DEFSLVS. Different
> > > > story is that devices aren't added to the subsystem yet. So what I have do in
> > > > that case is to enable to let HC operate and populate the bus later (using    
> > > > ->populate_bus() hook)    
> > > 
> > > Ahh I didn't see, you are calling it in two different places. Does it 
> > > make sense?
> > > 
> > > It is more logical to do the secondary_master_register() after get the 
> > > bus ownership (just need the first time), otherwise the HC is just a 
> > > slave.  
> > 
> > I think we've tried that approach, and I wasn't happy with the end
> > result. Don't remember the exact reason, but it was something related
> > to extra complexity related to init/registration steps in HC drivers.
> > You can look at my previous reviews if you want more details.  
> 
> I tested both cases and doing secondary_master_register() after get the 
> bus ownership I was able to reuse more code.

Fine, then post the code or push it somewhere so we can review it.

> 
> >   
> > > > > > > 
> > > > > > > In generally I found this intrusive for the current eco system.
> > > > > > > 
> > > > > > > I propose the following:
> > > > > > > 1 - Keep the function i3c_master_register() as is and go out before     
> > > > > > 
> > > > > > We had that version previously. We decided to split it.    
> > > > > 
> > > > > You just need to split the secondary master part from it. So you can go 
> > > > > out before i3c_master_bus_init() and keep the same function.    
> > > > 
> > > > We discussed that with Boris and we decided to split this function in this
> > > > version to make things clear.    
> > > 
> > > My proposal isn't to much different with the advantage that it not broke 
> > > the existing code.  
> > 
> > How do we break existing code? Can you please be more specific when you
> > make such statements so we can fix the problems. And no, keeping kernel
> > APIs/interfaces stable has never been our goal. Actually, it's quite the
> > opposite: the I3C subsystem is new, and if we see some of the initial
> > functions/interfaces/hooks do not apply well to some of the new
> > features we want to support, we should fix them, instead of trying to
> > workaround them.  
> 
> I wasn't able to apply the patch directly and I based my comments on the 
> tests that I made.
> During the process I didn't feel the need to work around anything (on 
> current API) to implement secondary master.

Sorry, didn't notice the DW driver was not patched in this series,
which is wrong. I guess that's what you meant when you said it was
breaking existing implems. Przemek, if you send a new version please
make sure to patch the DW driver to take API changes into account. Also
noticed that patch 4 breaks bisectability (users of the API should be
patched along with the API changes).

> 
> The secondary master is probably the most advanced feature in I3C and 
> since beginning I'm complaining that it just fit your use case.

I don't think it fits only 'my use case' since I personally have no
particular use case to support.

> Even now, I don't see clear how to fit slave API in this use case.

Slave API is completely orthogonal. All we need is a way for secondary
slaves to switch between slave and master roles, which I guess is
something HW specific anyway. In any case, secondary masters that want
to expose real features (by real I mean something more than just MR
support, like a GPIO controller, a sensor of whatever feature that can
be implemented by a slave-only device) will still have to register both
a slave and a master controller (we could add a wrapper registering
both, but that's just a detail). Each role will use a different set of
APIs/interfaces.

> In beginning when we started this secondary master topic, I pointed out 
> the i2c multi master approach and you the OTG from USB. So far I don't 
> see neither approach being used and we trying to reinvent the wheel.

Re-using what? You can't re-use the I2C or USB logic, simply because
none of them directly apply to I3C. What I said was that, conceptually,
I3C slave support would be something closer to USB gadgets than I2C
slaves, which has to do with how devices are exposed on the bus. The
concepts of BCR/DCR and PID look similar to the USB class, vendor and
product ID concepts and those are things that will be exposed by I3C
slave blocks so other masters on the bus can know what those slaves are
capable of and the standard interface (if any) they support.

> 
> Anyway I will try to come-up with a RFC based on what you are currently 
> working yet it is only for testing.
> Maybe we can split secondary master feature in phases:
>   - Sec Master initialization
>   - Mastership request
>   - Mastership deliver
>   - Mastership handoff
>   - Mastership takeover 
>   - Register DEFSLVS
>   - Restore SIR request from slaves
>   - Handle I3C device driver clients transfers on sec master side
> 
> It will be easier to follow the patches.

Well, if you can split it like that and keep bisectability intact
(that means each step in the series has to compile and work correctly),
then why not. In any case, please share the code you have so we can
discuss the implementation.

Thanks,

Boris

_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem
  2019-08-12 14:55                 ` Boris Brezillon
@ 2019-08-22 11:08                   ` Vitor Soares
  0 siblings, 0 replies; 21+ messages in thread
From: Vitor Soares @ 2019-08-22 11:08 UTC (permalink / raw)
  To: Boris Brezillon, Vitor Soares
  Cc: Przemyslaw Gaj, agolec, linux-i3c, rafalc, bbrezillon

Hi Boris,

From: Boris Brezillon <boris.brezillon@collabora.com>
Date: Mon, Aug 12, 2019 at 15:55:31

> > > > > > > > 
> > > > > > > > It is not clear to me what you expect with these functions. Do you want 
> > > > > > > > to enable MR from all devices? Just some of them? How do you decide which 
> > > > > > > > secondary masters are allow earn the bus ownership?
> > > > > > > >     
> > > > > > > 
> > > > > > > We discussed this also. For now, we enable ENEC for all masters on the bus, we
> > > > > > > can change it later if needed.     
> > > > > > 
> > > > > > I would say to expand the current ibi framework to accommodate MR and    
> > > > > 
> > > > > Can you tell something more here? What benefits you see    
> > > > 
> > > > Just starting with the name. IBI stands for In Band Interrupt which can 
> > > > be MR, HJ or SIR.
> > > > 
> > > > Also the concept is the same, let say you are registering a SIR w/out 
> > > > data but in fact it is a MR.  
> > > 
> > > No, it's not from a SW PoV. IBI are events I3C device drivers can
> > > register a handler for, MR and HJ events are things the HC drivers are
> > > expected to handle, and that's a big difference. While re-using the IBI
> > > API to handle them should be doable I don't think it will make things
> > > simpler.
> > >   
> > 
> > In that case we need to rename the functions with slave interrupt request 
> > (SIR) in mind.
> 
> I'm fine changing ibi for sir. Can you send a patch doing that?
> 

I address this topic on MIPI forum and it is correct to assume IBI as SIR 
and not MR.
With this clarification is not necessary to change the 
functions/structures/variables names.

Best regards,
Vitor Soares

_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v5 2/7] i3c: split i3c_master_register into init - register pair
  2019-06-22 20:55 ` [PATCH v5 2/7] i3c: split i3c_master_register into init - register pair Przemyslaw Gaj
  2019-07-06  8:48   ` Boris Brezillon
@ 2019-12-02 10:31   ` Przemyslaw Gaj
  1 sibling, 0 replies; 21+ messages in thread
From: Przemyslaw Gaj @ 2019-12-02 10:31 UTC (permalink / raw)
  To: vitor.soares; +Cc: linux-i3c, bbrezillon, rafalc, vitor.soares

Hi Vitor,

I know you didn't like this solution to split i3c_master_register. Could
you look into that once again?

Without that, I'm not able to satisfy the use case when secondary master
is registered after ENEC(MR) received already. That time registration path
is little bit different. It may be the case that we don't receive next
ENEC(MR) and won't be able to register all the devices / complete bus
initialization.

As it's different, it's good practice to split that routine and let HC drivers
register it differently. Without that, i3c_master_register becomes huge
and not readable, takes too many responsibilities.

Anyway, I updated DW HC driver also in that patch. I remember you and
Boris mentioned I didn't do that.

Can we discuss that aproach?

The 06/22/2019 21:55, Przemyslaw Gaj wrote:
> This patch is base for mastership takeover where secondary master is
> initialized at probe time but register may be postponed till dynamic address is
> assigned to our device.
> 
> Signed-off-by: Przemyslaw Gaj <pgaj@cadence.com>
> ---
>  drivers/i3c/master.c                 | 86 ++++++++++++++++++++----------------
>  drivers/i3c/master/dw-i3c-master.c   | 34 +++++++-------
>  drivers/i3c/master/i3c-master-cdns.c | 45 ++++++++++---------
>  include/linux/i3c/master.h           | 12 ++---
>  4 files changed, 94 insertions(+), 83 deletions(-)
> 
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index 0f7c31e..759078f 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -1528,32 +1528,9 @@ int i3c_master_do_daa(struct i3c_master_controller *master)
>  }
>  EXPORT_SYMBOL_GPL(i3c_master_do_daa);
>  
> -/**
> - * i3c_master_set_info() - set master device information
> - * @master: master used to send frames on the bus
> - * @info: I3C device information
> - *
> - * Set master device info. This should be called from
> - * &i3c_master_controller_ops->bus_init().
> - *
> - * Not all &i3c_device_info fields are meaningful for a master device.
> - * Here is a list of fields that should be properly filled:
> - *
> - * - &i3c_device_info->dyn_addr
> - * - &i3c_device_info->bcr
> - * - &i3c_device_info->dcr
> - * - &i3c_device_info->pid
> - * - &i3c_device_info->hdr_cap if %I3C_BCR_HDR_CAP bit is set in
> - *   &i3c_device_info->bcr
> - *
> - * This function must be called with the bus lock held in maintenance mode.
> - *
> - * Return: 0 if @info contains valid information (not every piece of
> - * information can be checked, but we can at least make sure @info->dyn_addr
> - * and @info->bcr are correct), -EINVAL otherwise.
> - */
> -int i3c_master_set_info(struct i3c_master_controller *master,
> -			const struct i3c_device_info *info)
> +static int i3c_master_set_info(struct i3c_master_controller *master,
> +			       const struct i3c_device_info *info,
> +			       bool secondary)
>  {
>  	struct i3c_dev_desc *i3cdev;
>  	int ret;
> @@ -1586,7 +1563,6 @@ int i3c_master_set_info(struct i3c_master_controller *master,
>  
>  	return ret;
>  }
> -EXPORT_SYMBOL_GPL(i3c_master_set_info);
>  
>  static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
>  {
> @@ -2403,7 +2379,7 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
>  }
>  
>  /**
> - * i3c_master_register() - register an I3C master
> + * i3c_master_init() - initializes all the structures required by I3C master
>   * @master: master used to send frames on the bus
>   * @parent: the parent device (the one that provides this I3C master
>   *	    controller)
> @@ -2417,16 +2393,14 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
>   * - creates and initializes the I3C bus
>   * - populates the bus with static I2C devs if @parent->of_node is not
>   *   NULL
> - * - registers all I3C devices added by the controller during bus
> - *   initialization
> - * - registers the I2C adapter and all I2C devices
> + * - set bus mode when registering I2C devices.
>   *
>   * Return: 0 in case of success, a negative error code otherwise.
>   */
> -int i3c_master_register(struct i3c_master_controller *master,
> -			struct device *parent,
> -			const struct i3c_master_controller_ops *ops,
> -			bool secondary)
> +int i3c_master_init(struct i3c_master_controller *master,
> +		    struct device *parent,
> +		    const struct i3c_master_controller_ops *ops,
> +		    bool secondary)
>  {
>  	struct i3c_bus *i3cbus = i3c_master_get_bus(master);
>  	enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
> @@ -2488,10 +2462,47 @@ int i3c_master_register(struct i3c_master_controller *master,
>  		ret = -ENOMEM;
>  		goto err_put_dev;
>  	}
> +	return 0;
> +
> +err_put_dev:
> +	put_device(&master->dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(i3c_master_init);
> +
> +void i3c_master_cleanup(struct i3c_master_controller *master)
> +{
> +	put_device(&master->dev);
> +}
> +EXPORT_SYMBOL_GPL(i3c_master_cleanup);
> +
> +/**
> + * i3c_master_register() - register an primary I3C master
> + * @master: master used to send frames on the bus
> + * @info: master info, describes this device
> + *
> + * This function takes care of everything for you:
> + *
> + * - updates this master info
> + * - registers all I3C devices added by the controller during bus
> + *   initialization
> + * - registers the I2C adapter and all I2C devices
> + *
> + * Return: 0 in case of success, a negative error code otherwise.
> + */
> +int i3c_master_register(struct i3c_master_controller *master,
> +			struct i3c_device_info *info)
> +{
> +	int ret;
> +
> +	ret = i3c_master_set_info(master, info, master->secondary);
> +	if (ret)
> +		return ret;
>  
>  	ret = i3c_master_bus_init(master);
>  	if (ret)
> -		goto err_put_dev;
> +		return ret;
>  
>  	ret = device_add(&master->dev);
>  	if (ret)
> @@ -2522,9 +2533,6 @@ int i3c_master_register(struct i3c_master_controller *master,
>  err_cleanup_bus:
>  	i3c_master_bus_cleanup(master);
>  
> -err_put_dev:
> -	put_device(&master->dev);
> -
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(i3c_master_register);
> diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
> index 22ac305..8e91364 100644
> --- a/drivers/i3c/master/dw-i3c-master.c
> +++ b/drivers/i3c/master/dw-i3c-master.c
> @@ -593,7 +593,6 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
>  {
>  	struct dw_i3c_master *master = to_dw_i3c_master(m);
>  	struct i3c_bus *bus = i3c_master_get_bus(m);
> -	struct i3c_device_info info = { };
>  	u32 thld_ctrl;
>  	int ret;
>  
> @@ -623,20 +622,6 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
>  	writel(INTR_MASTER_MASK, master->regs + INTR_STATUS_EN);
>  	writel(INTR_MASTER_MASK, master->regs + INTR_SIGNAL_EN);
>  
> -	ret = i3c_master_get_free_addr(m, 0);
> -	if (ret < 0)
> -		return ret;
> -
> -	writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret),
> -	       master->regs + DEVICE_ADDR);
> -
> -	memset(&info, 0, sizeof(info));
> -	info.dyn_addr = ret;
> -
> -	ret = i3c_master_set_info(&master->base, &info);
> -	if (ret)
> -		return ret;
> -
>  	writel(IBI_REQ_REJECT_ALL, master->regs + IBI_SIR_REQ_REJECT);
>  	writel(IBI_REQ_REJECT_ALL, master->regs + IBI_MR_REQ_REJECT);
>  
> @@ -1109,6 +1094,7 @@ static int dw_i3c_probe(struct platform_device *pdev)
>  {
>  	struct dw_i3c_master *master;
>  	struct resource *res;
> +	struct i3c_device_info info = { };
>  	int ret, irq;
>  
>  	master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
> @@ -1160,8 +1146,22 @@ static int dw_i3c_probe(struct platform_device *pdev)
>  	master->maxdevs = ret >> 16;
>  	master->free_pos = GENMASK(master->maxdevs - 1, 0);
>  
> -	ret = i3c_master_register(&master->base, &pdev->dev,
> -				  &dw_mipi_i3c_ops, false);
> +	ret = i3c_master_init(&master->base, &pdev->dev,
> +			      &dw_mipi_i3c_ops, false);
> +	if (ret)
> +		goto err_assert_rst;
> +
> +	ret = i3c_master_get_free_addr(&master->base, 0);
> +	if (ret < 0)
> +		goto err_assert_rst;
> +
> +	writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret),
> +	       master->regs + DEVICE_ADDR);
> +
> +	memset(&info, 0, sizeof(info));
> +	info.dyn_addr = ret;
> +
> +	ret = i3c_master_register(&master->base, &info);
>  	if (ret)
>  		goto err_assert_rst;
>  
> diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
> index 5aee315..9706426 100644
> --- a/drivers/i3c/master/i3c-master-cdns.c
> +++ b/drivers/i3c/master/i3c-master-cdns.c
> @@ -1193,8 +1193,7 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
>  	unsigned long pres_step, sysclk_rate, max_i2cfreq;
>  	struct i3c_bus *bus = i3c_master_get_bus(m);
>  	u32 ctrl, prescl0, prescl1, pres, low;
> -	struct i3c_device_info info = { };
> -	int ret, ncycles;
> +	int ncycles;
>  
>  	switch (bus->mode) {
>  	case I3C_BUS_MODE_PURE:
> @@ -1247,22 +1246,6 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
>  	prescl1 = PRESCL_CTRL1_OD_LOW(ncycles);
>  	writel(prescl1, master->regs + PRESCL_CTRL1);
>  
> -	/* Get an address for the master. */
> -	ret = i3c_master_get_free_addr(m, 0);
> -	if (ret < 0)
> -		return ret;
> -
> -	writel(prepare_rr0_dev_address(ret) | DEV_ID_RR0_IS_I3C,
> -	       master->regs + DEV_ID_RR0(0));
> -
> -	cdns_i3c_master_dev_rr_to_info(master, 0, &info);
> -	if (info.bcr & I3C_BCR_HDR_CAP)
> -		info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
> -
> -	ret = i3c_master_set_info(&master->base, &info);
> -	if (ret)
> -		return ret;
> -
>  	/*
>  	 * Enable Hot-Join, and, when a Hot-Join request happens, disable all
>  	 * events coming from this device.
> @@ -1531,6 +1514,7 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
>  {
>  	struct cdns_i3c_master *master;
>  	struct resource *res;
> +	struct i3c_device_info info = { };
>  	int ret, irq;
>  	u32 val;
>  
> @@ -1606,13 +1590,32 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
>  	writel(MST_INT_IBIR_THR, master->regs + MST_IER);
>  	writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
>  
> -	ret = i3c_master_register(&master->base, &pdev->dev,
> -				  &cdns_i3c_master_ops, false);
> +	ret = i3c_master_init(&master->base, &pdev->dev, &cdns_i3c_master_ops, false);
>  	if (ret)
> -		goto err_disable_sysclk;
> +	goto err_disable_sysclk;
> +
> +	/* Get an address for the master. */
> +	ret = i3c_master_get_free_addr(&master->base, 0);
> +	if (ret < 0)
> +		return ret;
> +
> +	writel(prepare_rr0_dev_address(ret) | DEV_ID_RR0_IS_I3C,
> +	       master->regs + DEV_ID_RR0(0));
> +
> +	cdns_i3c_master_dev_rr_to_info(master, 0, &info);
> +	if (info.bcr & I3C_BCR_HDR_CAP)
> +		info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
> +
> +	ret = i3c_master_register(&master->base, &info);
> +
> +	if (ret)
> +		goto err_cleanup;
>  
>  	return 0;
>  
> +err_cleanup:
> +	i3c_master_cleanup(&master->base);
> +
>  err_disable_sysclk:
>  	clk_disable_unprepare(master->sysclk);
>  
> diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
> index 42bb215..df3d769 100644
> --- a/include/linux/i3c/master.h
> +++ b/include/linux/i3c/master.h
> @@ -530,13 +530,13 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
>  				  u8 addr);
>  int i3c_master_do_daa(struct i3c_master_controller *master);
>  
> -int i3c_master_set_info(struct i3c_master_controller *master,
> -			const struct i3c_device_info *info);
> -
> +int i3c_master_init(struct i3c_master_controller *master,
> +		    struct device *parent,
> +		    const struct i3c_master_controller_ops *ops,
> +		    bool secondary);
> +void i3c_master_cleanup(struct i3c_master_controller *master);
>  int i3c_master_register(struct i3c_master_controller *master,
> -			struct device *parent,
> -			const struct i3c_master_controller_ops *ops,
> -			bool secondary);
> +			struct i3c_device_info *info);
>  int i3c_master_unregister(struct i3c_master_controller *master);
>  
>  /**
> -- 
> 2.4.5
> 

-- 
--
Regards,
Przemek

_______________________________________________
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, back to index

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-22 20:54 [PATCH v5 0/7] Add the I3C mastership request Przemyslaw Gaj
2019-06-22 20:54 ` [PATCH v5 1/7] i3c: add addr and lvr to i2c_dev_desc structure Przemyslaw Gaj
2019-06-22 20:55 ` [PATCH v5 2/7] i3c: split i3c_master_register into init - register pair Przemyslaw Gaj
2019-07-06  8:48   ` Boris Brezillon
2019-12-02 10:31   ` Przemyslaw Gaj
2019-06-22 20:55 ` [PATCH v5 3/7] i3c: export i3c_bus_set_mode function Przemyslaw Gaj
2019-07-06  7:39   ` Boris Brezillon
2019-06-22 20:55 ` [PATCH v5 4/7] i3c: Add support for mastership request to I3C subsystem Przemyslaw Gaj
2019-07-06  9:00   ` Boris Brezillon
2019-07-10 18:04   ` Vitor Soares
2019-07-11  5:28     ` Przemyslaw Gaj
2019-07-11 10:11       ` Vitor Soares
2019-07-12 10:10         ` Przemyslaw Gaj
2019-07-12 11:28           ` Vitor Soares
2019-08-11 10:17             ` Boris Brezillon
2019-08-12 13:55               ` Vitor Soares
2019-08-12 14:55                 ` Boris Brezillon
2019-08-22 11:08                   ` Vitor Soares
2019-06-22 20:55 ` [PATCH v5 5/7] i3c: master: cdns: add support for mastership request to Cadence I3C master driver Przemyslaw Gaj
2019-06-22 20:55 ` [PATCH v5 6/7] i3c: master: Add module author Przemyslaw Gaj
2019-06-22 20:55 ` [PATCH v5 7/7] MAINTAINERS: add myself as co-maintainer of i3c subsystem Przemyslaw Gaj

Linux-i3c Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-i3c/0 linux-i3c/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-i3c linux-i3c/ https://lore.kernel.org/linux-i3c \
		linux-i3c@lists.infradead.org
	public-inbox-index linux-i3c

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.infradead.lists.linux-i3c


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git