lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1586211703-8862-1-git-send-email-pthombar@cadence.com>
Date:   Tue, 7 Apr 2020 00:21:43 +0200
From:   Parshuram Thombare <pthombar@...ence.com>
To:     <bbrezillon@...nel.org>, <vitor.soares@...opsys.com>
CC:     <pgaj@...ence.com>, <linux-i3c@...ts.infradead.org>,
        <linux-kernel@...r.kernel.org>, <mparab@...ence.com>,
        Parshuram Thombare <pthombar@...ence.com>
Subject: [PATCH v1 2/3] i3c: add mastership handover support to i3c master subsystem

This patch adds mastership handover support to I3C master
subsystem as per MIPI I3C v1.0 specification.

Signed-off-by: Parshuram Thombare <pthombar@...ence.com>
---
 drivers/i3c/master.c       | 486 ++++++++++++++++++++++++++++++++++---
 include/linux/i3c/master.h |  40 +++
 2 files changed, 487 insertions(+), 39 deletions(-)

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 0ec332e45737..42b6385fc3c8 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -963,6 +963,33 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master)
 }
 EXPORT_SYMBOL_GPL(i3c_master_defslvs_locked);
 
+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;
+}
+
 static int i3c_master_setda_locked(struct i3c_master_controller *master,
 				   u8 oldaddr, u8 newaddr, bool setdasa)
 {
@@ -1525,6 +1552,185 @@ int i3c_master_do_daa(struct i3c_master_controller *master)
 }
 EXPORT_SYMBOL_GPL(i3c_master_do_daa);
 
+static int i3c_master_getaccmst(struct i3c_master_controller *master)
+{
+	int ret;
+
+	i3c_bus_maintenance_lock(&master->bus);
+	ret = i3c_master_get_accmst_locked(master, master->mr_addr);
+	i3c_bus_maintenance_unlock(&master->bus);
+
+	return ret;
+}
+
+static int i3c_master_request_mastership(struct i3c_master_controller *master)
+{
+	int ret;
+
+	/* request_mastership callback should handle EN/DIS EC MR.*/
+	i3c_bus_maintenance_lock(&master->bus);
+	ret = master->ops->request_mastership(master);
+	i3c_bus_maintenance_unlock(&master->bus);
+
+	return ret;
+}
+
+static void i3c_mst_yield_bus(struct work_struct *work)
+{
+	struct i3c_master_controller *m;
+	struct i3c_dev_desc *i3cdev;
+	int ret;
+
+	m = container_of(work, struct i3c_master_controller, mst_work);
+	switch (m->mr_state) {
+	case I3C_MR_DISEC_MR:
+		/*
+		 * Disable MR on all but the secondary master first
+		 * reaching here.
+		 */
+		i3c_bus_for_each_i3cdev(&m->bus, i3cdev) {
+			if (I3C_BCR_DEVICE_ROLE(i3cdev->info.bcr) !=
+			    I3C_BCR_I3C_MASTER ||
+			    i3cdev->info.dyn_addr == m->mr_addr ||
+			    m->this == i3cdev)
+				continue;
+			i3c_bus_maintenance_lock(&m->bus);
+			i3c_master_disec_locked(m, i3cdev->info.dyn_addr,
+						I3C_CCC_EVENT_MR);
+			i3c_bus_maintenance_unlock(&m->bus);
+		}
+		m->mr_state = I3C_MR_GETACCMST;
+		queue_work(m->wq, &m->mst_work);
+		break;
+
+	case I3C_MR_GETACCMST:
+		ret = i3c_master_getaccmst(m);
+		if (!ret)
+			m->mr_state = I3C_MR_DONE;
+		else
+			m->mr_state = I3C_MR_FAILED;
+		queue_work(m->wq, &m->mst_work);
+		break;
+
+	case I3C_MR_DONE:
+		i3c_bus_for_each_i3cdev(&m->bus, i3cdev) {
+			if (m->mr_addr == i3cdev->info.dyn_addr) {
+				m->bus.cur_master = i3cdev;
+				break;
+			}
+		}
+		m->mr_state = I3C_MR_IDLE;
+		break;
+
+	case I3C_MR_FAILED:
+		m->ops->enable_mr_events(m);
+		i3c_bus_maintenance_lock(&m->bus);
+		i3c_master_enec_locked(m, I3C_BROADCAST_ADDR,
+				       I3C_CCC_EVENT_MR);
+		i3c_bus_maintenance_unlock(&m->bus);
+		m->mr_state = I3C_MR_IDLE;
+		break;
+
+	default:
+		break;
+	}
+}
+
+void
+i3c_master_yield_bus(struct i3c_master_controller *master, u8 sec_mst_dyn_addr)
+{
+	master->ops->disable_mr_events(master);
+	master->mr_addr = sec_mst_dyn_addr;
+	master->mr_state = I3C_MR_DISEC_MR;
+	queue_work(master->wq, &master->mst_work);
+}
+EXPORT_SYMBOL_GPL(i3c_master_yield_bus);
+
+static void i3c_sec_mst_acquire_bus(struct work_struct *work)
+{
+	struct i3c_master_controller *m;
+	struct i3c_bus *i3cbus;
+	int ret;
+
+	m = container_of(work, struct i3c_master_controller, sec_mst_work);
+	i3cbus = i3c_master_get_bus(m);
+	switch (m->mr_state) {
+	case I3C_MR_WAIT_DA:
+		/* Wait until this master have dynamic address */
+		if (m->ops->check_event_set(m, I3C_SLV_DA_UPDATE))
+			m->mr_state = I3C_MR_REQUEST;
+		queue_work(m->wq, &m->sec_mst_work);
+		break;
+
+	case I3C_MR_REQUEST:
+		/* Wait until we can send MR */
+		ret = i3c_master_request_mastership(m);
+		if (!ret)
+			m->mr_state = I3C_MR_WAIT_DEFSLVS;
+		queue_work(m->wq, &m->sec_mst_work);
+		break;
+
+	case I3C_MR_WAIT_DEFSLVS:
+		/*
+		 * Wait for DEFSLVS, this event check should make sure
+		 * that DEFSLVS list is read into m->defslvs_data
+		 */
+		if (m->ops->check_event_set(m, I3C_SLV_DEFSLVS_CCC))
+			m->mr_state = I3C_MR_WAIT_MR_DONE;
+		queue_work(m->wq, &m->sec_mst_work);
+		break;
+
+	case I3C_MR_WAIT_MR_DONE:
+		if (m->ops->check_event_set(m, I3C_SLV_MR_DONE)) {
+			m->mr_state = I3C_MR_DONE;
+			complete(&m->mr_comp);
+		} else {
+			queue_work(m->wq, &m->sec_mst_work);
+		}
+		break;
+
+	default:
+		m->mr_state = I3C_MR_FAILED;
+		complete(&m->mr_comp);
+		break;
+	}
+}
+
+void i3c_sec_mst_mr_dis_event(struct i3c_master_controller *m)
+{
+	if (m->mr_state != I3C_MR_IDLE)
+		m->mr_state = I3C_MR_WAIT_DA;
+}
+EXPORT_SYMBOL_GPL(i3c_sec_mst_mr_dis_event);
+
+static int i3c_master_acquire_bus(struct i3c_master_controller *master)
+{
+	int ret = 0;
+
+	if (!master->this || master->this != master->bus.cur_master) {
+		i3c_bus_normaluse_lock(&master->bus);
+		if (master->mr_state == I3C_MR_IDLE) {
+			master->mr_state = I3C_MR_WAIT_DA;
+			i3c_bus_normaluse_unlock(&master->bus);
+			init_completion(&master->mr_comp);
+			queue_work(master->wq, &master->sec_mst_work);
+			wait_for_completion(&master->mr_comp);
+			if (master->mr_state != I3C_MR_DONE)
+				ret = -EAGAIN;
+			master->mr_state = I3C_MR_IDLE;
+		} else {
+			/*
+			 * MR request is already in process for
+			 * this master
+			 */
+			ret = -EAGAIN;
+			i3c_bus_normaluse_unlock(&master->bus);
+		}
+	}
+
+	return ret;
+}
+
 /**
  * i3c_master_set_info() - set master device information
  * @master: master used to send frames on the bus
@@ -1558,10 +1764,6 @@ 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;
 
@@ -1622,9 +1824,10 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
  * 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)
+ * 2. Should have called &i3c_master_controller_ops->bus_init()
+ *    method with pure bus mode 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
@@ -1708,14 +1911,6 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
 		}
 	}
 
-	/*
-	 * Now execute the controller specific ->bus_init() routine, which
-	 * might configure its internal logic to match the bus limitations.
-	 */
-	ret = master->ops->bus_init(master);
-	if (ret)
-		goto err_detach_devs;
-
 	ret = master->ops->master_set_info(master);
 	if (ret)
 		goto err_detach_devs;
@@ -1728,7 +1923,7 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
 		dev_err(&master->dev,
 			"master_set_info() was not called in ->bus_init()\n");
 		ret = -EINVAL;
-		goto err_bus_cleanup;
+		goto err_detach_devs;
 	}
 
 	/*
@@ -1737,14 +1932,14 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
 	 */
 	ret = i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR);
 	if (ret && ret != I3C_ERROR_M2)
-		goto err_bus_cleanup;
+		goto err_detach_devs;
 
 	/* Disable all slave events before starting DAA. */
 	ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR,
 				      I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR |
 				      I3C_CCC_EVENT_HJ);
 	if (ret && ret != I3C_ERROR_M2)
-		goto err_bus_cleanup;
+		goto err_detach_devs;
 
 	/*
 	 * Pre-assign dynamic address and retrieve device information if
@@ -1762,10 +1957,6 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
 err_rstdaa:
 	i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR);
 
-err_bus_cleanup:
-	if (master->ops->bus_cleanup)
-		master->ops->bus_cleanup(master);
-
 err_detach_devs:
 	i3c_master_detach_free_devs(master);
 
@@ -2249,6 +2440,9 @@ void i3c_generic_ibi_free_pool(struct i3c_generic_ibi_pool *pool)
 	struct i3c_generic_ibi_slot *slot;
 	unsigned int nslots = 0;
 
+	if (!pool)
+		return;
+
 	while (!list_empty(&pool->free_slots)) {
 		slot = list_first_entry(&pool->free_slots,
 					struct i3c_generic_ibi_slot, node);
@@ -2392,9 +2586,179 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
 	     !ops->recycle_ibi_slot))
 		return -EINVAL;
 
+	if (ops->request_mastership &&
+	    (!ops->enable_mr_events || !ops->disable_mr_events ||
+	     !ops->check_event_set))
+		return -EINVAL;
+
 	return 0;
 }
 
+static struct i2c_dev_boardinfo *
+i3c_master_alloc_i2c_boardinfo(struct i3c_master_controller *master,
+			       u16 addr, u8 lvr)
+{
+	struct i2c_dev_boardinfo *i2cboardinfo;
+
+	i2cboardinfo = kzalloc(sizeof(*i2cboardinfo), GFP_KERNEL);
+	if (!i2cboardinfo)
+		return ERR_PTR(-ENOMEM);
+
+	i2cboardinfo->base.addr = addr;
+	i2cboardinfo->lvr = lvr;
+
+	return i2cboardinfo;
+}
+
+static int i3c_secondary_master_bus_init(struct i3c_master_controller *master)
+{
+	struct i3c_ccc_dev_desc *desc;
+	struct i3c_dev_desc *i3cdev;
+	struct i2c_dev_desc *i2cdev;
+	struct i2c_dev_boardinfo *info;
+	int ret, slot;
+
+	desc = master->defslvs_data.devs;
+	for (slot = 1; slot <= master->defslvs_data.ndevs; slot++, desc++) {
+		if (desc->static_addr) {
+			i3c_bus_set_addr_slot_status(&master->bus,
+						     desc->static_addr,
+						     I3C_ADDR_SLOT_I2C_DEV);
+			info = i3c_master_alloc_i2c_boardinfo(master,
+							      desc->static_addr,
+							      desc->lvr);
+			if (IS_ERR(info)) {
+				ret = PTR_ERR(info);
+				goto err_detach_devs;
+			}
+
+			i2cdev = i3c_master_alloc_i2c_dev(master, info);
+			if (IS_ERR(i2cdev)) {
+				ret = PTR_ERR(i2cdev);
+				goto err_detach_devs;
+			}
+
+			ret = i3c_master_attach_i2c_dev(master, i2cdev);
+			if (ret) {
+				i3c_master_free_i2c_dev(i2cdev);
+				goto err_detach_devs;
+			}
+		} else {
+			struct i3c_device_info info = {
+				.dyn_addr = desc->dyn_addr,
+			};
+
+			i3cdev = i3c_master_alloc_i3c_dev(master, &info);
+			if (IS_ERR(i3cdev)) {
+				ret = PTR_ERR(i3cdev);
+				goto err_detach_devs;
+			}
+
+			ret = i3c_master_attach_i3c_dev(master, i3cdev);
+			if (ret) {
+				i3c_master_free_i3c_dev(i3cdev);
+				goto err_detach_devs;
+			}
+		}
+	}
+
+	ret = master->ops->master_set_info(master);
+	if (ret)
+		goto err_bus_cleanup;
+
+	i3c_bus_for_each_i3cdev(&master->bus, i3cdev) {
+		if (master->this != i3cdev) {
+			ret = i3c_master_retrieve_dev_info(i3cdev);
+			if (ret)
+				goto err_bus_cleanup;
+		}
+	}
+
+	if (!master->this) {
+		dev_err(&master->dev,
+			"master_set_info() was not called in ->bus_init()\n");
+		ret = -EINVAL;
+		goto err_bus_cleanup;
+	}
+
+	return 0;
+
+err_bus_cleanup:
+	if (master->ops->bus_cleanup)
+		master->ops->bus_cleanup(master);
+
+err_detach_devs:
+	i3c_master_detach_free_devs(master);
+
+	return ret;
+}
+
+static void i3c_secondary_master_register(struct work_struct *work)
+{
+	struct i3c_master_controller *master;
+	struct i3c_bus *i3cbus;
+	int ret;
+
+	master = container_of(work, struct i3c_master_controller,
+			      sec_mst_register_work);
+	i3cbus = i3c_master_get_bus(master);
+
+	ret = i3c_master_acquire_bus(master);
+	if (ret)
+		goto err_cleanup_bus;
+
+	/* Again bus_init to bus_mode, based on data received in DEFSLVS */
+	ret = i3c_bus_set_mode(i3cbus, master->defslvs_data.bus_mode);
+	if (ret)
+		goto err_cleanup_bus;
+
+	ret = master->ops->bus_init(master);
+	if (ret)
+		goto err_cleanup_bus;
+
+	ret = i3c_secondary_master_bus_init(master);
+	if (ret)
+		goto err_cleanup_bus;
+
+	ret = device_add(&master->dev);
+	if (ret)
+		goto err_cleanup_bus;
+
+	/*
+	 * 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;
+
+	/*
+	 * We're done initializing the bus and the controller, we can now
+	 * register I3C devices from defslvs list.
+	 */
+	master->init_done = true;
+	i3c_bus_normaluse_lock(&master->bus);
+	i3c_master_register_new_i3c_devs(master);
+	i3c_bus_normaluse_unlock(&master->bus);
+
+	master->ops->enable_mr_events(master);
+	i3c_bus_maintenance_lock(&master->bus);
+	ret = i3c_master_enec_locked(master, I3C_BROADCAST_ADDR,
+				     I3C_CCC_EVENT_MR);
+	i3c_bus_maintenance_unlock(&master->bus);
+
+	return;
+
+err_del_dev:
+	device_del(&master->dev);
+
+err_cleanup_bus:
+	if (master->ops->bus_cleanup)
+		master->ops->bus_cleanup(master);
+
+	put_device(&master->dev);
+}
+
 /**
  * i3c_master_register() - register an I3C master
  * @master: master used to send frames on the bus
@@ -2424,10 +2788,10 @@ int i3c_master_register(struct i3c_master_controller *master,
 	struct i3c_bus *i3cbus = i3c_master_get_bus(master);
 	enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
 	struct i2c_dev_boardinfo *i2cbi;
-	int ret;
+	int ret, sz;
 
-	/* We do not support secondary masters yet. */
-	if (secondary)
+	/*Check if controller driver supports secondary masters. */
+	if (secondary && !ops->request_mastership)
 		return -ENOTSUPP;
 
 	ret = i3c_master_check_ops(ops);
@@ -2451,10 +2815,45 @@ int i3c_master_register(struct i3c_master_controller *master,
 	device_initialize(&master->dev);
 	dev_set_name(&master->dev, "i3c-%d", i3cbus->id);
 
-	ret = of_populate_i3c_bus(master);
+	master->wq = alloc_workqueue("%s", 0, 0, dev_name(parent));
+	if (!master->wq) {
+		ret = -ENOMEM;
+		goto err_put_dev;
+	}
+
+	master->mr_state = I3C_MR_IDLE;
+	INIT_WORK(&master->sec_mst_work, i3c_sec_mst_acquire_bus);
+	INIT_WORK(&master->mst_work, i3c_mst_yield_bus);
+
+	ret = i3c_bus_set_mode(i3cbus, mode);
+	if (ret)
+		goto err_put_dev;
+
+	/*
+	 * Now execute the controller specific ->bus_init() routine, which
+	 * might configure its internal logic to match the bus limitations.
+	 */
+	ret = master->ops->bus_init(master);
 	if (ret)
 		goto err_put_dev;
 
+	if (secondary) {
+		sz = sizeof(struct i3c_ccc_dev_desc) * I3C_BUS_MAX_DEVS;
+		master->defslvs_data.devs = devm_kzalloc(&master->dev, sz,
+							 GFP_KERNEL);
+		if (!master->defslvs_data.devs)
+			goto err_put_dev;
+
+		INIT_WORK(&master->sec_mst_register_work,
+			  i3c_secondary_master_register);
+		queue_work(master->wq, &master->sec_mst_register_work);
+		return 0;
+	}
+
+	ret = of_populate_i3c_bus(master);
+	if (ret)
+		goto err_cleanup_bus;
+
 	list_for_each_entry(i2cbi, &master->boardinfo.i2c, node) {
 		switch (i2cbi->lvr & I3C_LVR_I2C_INDEX_MASK) {
 		case I3C_LVR_I2C_INDEX(0):
@@ -2468,23 +2867,13 @@ int i3c_master_register(struct i3c_master_controller *master,
 			break;
 		default:
 			ret = -EINVAL;
-			goto err_put_dev;
+			goto err_cleanup_bus;
 		}
 	}
 
-	ret = i3c_bus_set_mode(i3cbus, mode);
-	if (ret)
-		goto err_put_dev;
-
-	master->wq = alloc_workqueue("%s", 0, 0, dev_name(parent));
-	if (!master->wq) {
-		ret = -ENOMEM;
-		goto err_put_dev;
-	}
-
 	ret = i3c_master_bus_init(master);
 	if (ret)
-		goto err_put_dev;
+		goto err_cleanup_bus;
 
 	ret = device_add(&master->dev);
 	if (ret)
@@ -2507,6 +2896,22 @@ int i3c_master_register(struct i3c_master_controller *master,
 	i3c_master_register_new_i3c_devs(master);
 	i3c_bus_normaluse_unlock(&master->bus);
 
+	if (ops->request_mastership) {
+		master->ops->enable_mr_events(master);
+		i3c_bus_maintenance_lock(&master->bus);
+		i3c_master_enec_locked(master, I3C_BROADCAST_ADDR,
+				       I3C_CCC_EVENT_MR);
+		i3c_bus_maintenance_unlock(&master->bus);
+	}
+
+	ret = i3c_bus_set_mode(i3cbus, mode);
+	if (ret)
+		goto err_del_dev;
+
+	ret = master->ops->bus_init(master);
+	if (ret)
+		goto err_del_dev;
+
 	return 0;
 
 err_del_dev:
@@ -2557,7 +2962,10 @@ int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
 	if (!master->ops->priv_xfers)
 		return -ENOTSUPP;
 
-	return master->ops->priv_xfers(dev, xfers, nxfers);
+	if (!i3c_master_acquire_bus(master))
+		return master->ops->priv_xfers(dev, xfers, nxfers);
+	else
+		return -EAGAIN;
 }
 
 int i3c_dev_disable_ibi_locked(struct i3c_dev_desc *dev)
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index 3dc7eafe811a..c6427c62ed83 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -259,6 +259,27 @@ enum i3c_bus_mode {
 	I3C_BUS_MODE_MIXED_SLOW,
 };
 
+enum i3c_mr_state {
+	I3C_MR_IDLE,
+	I3C_MR_DISEC_MR,
+	I3C_MR_SEND_DEFSLVS,
+	I3C_MR_GETACCMST,
+	I3C_MR_WAIT_DA,
+	I3C_MR_CHECK_STATE,
+	I3C_MR_REQUEST,
+	I3C_MR_WAIT_DEFSLVS,
+	I3C_MR_WAIT_MR_DONE,
+	I3C_MR_DONE,
+	I3C_MR_FAILED,
+};
+
+enum i3c_event {
+	I3C_SLV_DA_UPDATE,
+	I3C_SLV_DEFSLVS_CCC,
+	I3C_SLV_MR_DIS,
+	I3C_SLV_MR_DONE,
+};
+
 /**
  * enum i3c_addr_slot_status - I3C address slot status
  * @I3C_ADDR_SLOT_FREE: address is free
@@ -448,6 +469,11 @@ 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);
+	void (*enable_mr_events)(struct i3c_master_controller *m);
+	void (*disable_mr_events)(struct i3c_master_controller *m);
+	bool (*check_event_set)(struct i3c_master_controller *m,
+				enum i3c_event);
 };
 
 /**
@@ -489,6 +515,17 @@ struct i3c_master_controller {
 	} boardinfo;
 	struct i3c_bus bus;
 	struct workqueue_struct *wq;
+	struct work_struct sec_mst_register_work;
+	struct work_struct mst_work;
+	struct work_struct sec_mst_work;
+	struct completion mr_comp;
+	enum i3c_mr_state mr_state;
+	u8 mr_addr;
+	struct {
+		u32 ndevs;
+		enum i3c_bus_mode bus_mode;
+		struct i3c_ccc_dev_desc *devs;
+	} defslvs_data;
 };
 
 /**
@@ -513,6 +550,9 @@ struct i3c_master_controller {
 #define i3c_bus_for_each_i3cdev(bus, dev)				\
 	list_for_each_entry(dev, &(bus)->devs.i3c, common.node)
 
+void i3c_master_yield_bus(struct i3c_master_controller *master,
+			  u8 slv_dyn_addr);
+void i3c_sec_mst_mr_dis_event(struct i3c_master_controller *m);
 int i3c_master_do_i2c_xfers(struct i3c_master_controller *master,
 			    const struct i2c_msg *xfers,
 			    int nxfers);
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ