linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] I3C slave mode support
@ 2023-10-18 21:58 Frank Li
  2023-10-18 21:58 ` [PATCH 1/5] i3c: add " Frank Li
                   ` (4 more replies)
  0 siblings, 5 replies; 17+ messages in thread
From: Frank Li @ 2023-10-18 21:58 UTC (permalink / raw)
  To: miquel.raynal, conor.culhane, alexandre.belloni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, joe, Frank.Li,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: gregkh, imx, jirislaby, linux-serial

This  patch introduces support for I3C slave mode, which is referenced
with a PCIe Endpoint system. It also establishes a configuration framework
(configfs) for the I3C slave controller driver and the I3C slave function
driver

Typic usage as

The user can configure the i3c-slave-tty device using configfs entry. In
order to change the vendorid, the following commands can be used

        # echo 0x011b > functions/tty/func1/vendor_id
        # echo 0x1000 > functions/tty/func1/part_id
        # echo 0x6 > functions/tty/t/bcr

Binding i3c-slave-tty Device to slave Controller
------------------------------------------------

In order for the slave function device to be useful, it has to be bound to
a I3C slave controller driver. Use the configfs to bind the function
device to one of the controller driver present in the system::

        # ln -s functions/pci_epf_test/func1 controllers/44330000.i3c-slave/

Host side:
        cat /dev/ttyI3C0
Slave side:
        echo abc >/dev/ttyI3C0

Master side patch:
https://lore.kernel.org/imx/20231018211111.3437929-1-Frank.Li@nxp.com/T/#u

Frank Li (5):
  i3c: add slave mode support
  dt-bindings: i3c: svc: add compatible string i3c: silvaco,i3c-slave
  i3c: slave: add svc slave controller support
  i3c: slave: func: add tty driver
  Documentation: i3c: Add I3C slave mode controller and function

 .../bindings/i3c/silvaco,i3c-master.yaml      |   8 +-
 Documentation/driver-api/i3c/index.rst        |   1 +
 .../driver-api/i3c/slave/i3c-slave-cfs.rst    | 109 +++
 .../driver-api/i3c/slave/i3c-slave.rst        | 189 +++++
 .../driver-api/i3c/slave/i3c-tty-function.rst | 103 +++
 .../driver-api/i3c/slave/i3c-tty-howto.rst    | 109 +++
 Documentation/driver-api/i3c/slave/index.rst  |  13 +
 drivers/i3c/Kconfig                           |  30 +
 drivers/i3c/Makefile                          |   4 +
 drivers/i3c/func/Kconfig                      |   9 +
 drivers/i3c/func/Makefile                     |   3 +
 drivers/i3c/func/tty.c                        | 548 ++++++++++++
 drivers/i3c/i3c-cfs.c                         | 389 +++++++++
 drivers/i3c/slave.c                           | 453 ++++++++++
 drivers/i3c/slave/Kconfig                     |   9 +
 drivers/i3c/slave/Makefile                    |   4 +
 drivers/i3c/slave/svc-i3c-slave.c             | 795 ++++++++++++++++++
 include/linux/i3c/slave.h                     | 503 +++++++++++
 18 files changed, 3276 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/driver-api/i3c/slave/i3c-slave-cfs.rst
 create mode 100644 Documentation/driver-api/i3c/slave/i3c-slave.rst
 create mode 100644 Documentation/driver-api/i3c/slave/i3c-tty-function.rst
 create mode 100644 Documentation/driver-api/i3c/slave/i3c-tty-howto.rst
 create mode 100644 Documentation/driver-api/i3c/slave/index.rst
 create mode 100644 drivers/i3c/func/Kconfig
 create mode 100644 drivers/i3c/func/Makefile
 create mode 100644 drivers/i3c/func/tty.c
 create mode 100644 drivers/i3c/i3c-cfs.c
 create mode 100644 drivers/i3c/slave.c
 create mode 100644 drivers/i3c/slave/Kconfig
 create mode 100644 drivers/i3c/slave/Makefile
 create mode 100644 drivers/i3c/slave/svc-i3c-slave.c
 create mode 100644 include/linux/i3c/slave.h

-- 
2.34.1


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

* [PATCH 1/5] i3c: add slave mode support
  2023-10-18 21:58 [PATCH 0/5] I3C slave mode support Frank Li
@ 2023-10-18 21:58 ` Frank Li
  2023-10-19  7:00   ` Krzysztof Kozlowski
                     ` (2 more replies)
  2023-10-18 21:58 ` [PATCH 2/5] dt-bindings: i3c: svc: add compatible string i3c: silvaco,i3c-slave Frank Li
                   ` (3 subsequent siblings)
  4 siblings, 3 replies; 17+ messages in thread
From: Frank Li @ 2023-10-18 21:58 UTC (permalink / raw)
  To: miquel.raynal, conor.culhane, alexandre.belloni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, joe, Frank.Li,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: gregkh, imx, jirislaby, linux-serial

Introduce a new slave core layer in order to support slave functions in
linux kernel. This comprises the controller library and function library.
Controller library implements functions specific to an slave controller
and function library implements functions specific to an slave function.

Introduce a new configfs entry to configure the slave function configuring
and bind the slave function with slave controller.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 drivers/i3c/Kconfig       |  26 ++
 drivers/i3c/Makefile      |   2 +
 drivers/i3c/i3c-cfs.c     | 389 +++++++++++++++++++++++++++++
 drivers/i3c/slave.c       | 453 ++++++++++++++++++++++++++++++++++
 include/linux/i3c/slave.h | 503 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 1373 insertions(+)
 create mode 100644 drivers/i3c/i3c-cfs.c
 create mode 100644 drivers/i3c/slave.c
 create mode 100644 include/linux/i3c/slave.h

diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig
index 30a441506f61c..d5f5ca7cd6a56 100644
--- a/drivers/i3c/Kconfig
+++ b/drivers/i3c/Kconfig
@@ -22,3 +22,29 @@ menuconfig I3C
 if I3C
 source "drivers/i3c/master/Kconfig"
 endif # I3C
+
+config I3C_SLAVE
+	bool "I3C Slave Support"
+	help
+	  Support I3C Slave Mode.
+
+	  Enable this configuration option to support configurable I3C slave.
+	  This should be enabled if the platform has a I3C controller that can
+	  operate in slave mode.
+
+	  Enabling this option will build the I3C slave library, which includes
+	  slave controller library and slave function library.
+
+	  If in doubt, say "N" to disable slave support.
+
+config I3C_SLAVE_CONFIGFS
+	bool "I3C Slave Configfs Support"
+	depends on I3C_SLAVE
+	select CONFIGFS_FS
+	help
+	  Configfs entry for slave function and controller.
+
+	  This will enable the configfs entry that can be used to configure
+	  the slave function and used to bind the function with a slave
+	  controller.
+
diff --git a/drivers/i3c/Makefile b/drivers/i3c/Makefile
index 11982efbc6d91..6407ddec3a4a9 100644
--- a/drivers/i3c/Makefile
+++ b/drivers/i3c/Makefile
@@ -2,3 +2,5 @@
 i3c-y				:= device.o master.o
 obj-$(CONFIG_I3C)		+= i3c.o
 obj-$(CONFIG_I3C)		+= master/
+obj-$(CONFIG_I3C_SLAVE)		+= slave.o
+obj-$(CONFIG_I3C_SLAVE_CONFIGFS)	+= i3c-cfs.o
diff --git a/drivers/i3c/i3c-cfs.c b/drivers/i3c/i3c-cfs.c
new file mode 100644
index 0000000000000..35e07da50ebb0
--- /dev/null
+++ b/drivers/i3c/i3c-cfs.c
@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Configfs to configure the I3C Slave
+ *
+ * Copyright (C) 2023 NXP
+ * Author: Frank Li <Frank.Li@nxp.com>
+ */
+
+#include <linux/configfs.h>
+#include <linux/module.h>
+#include <linux/i3c/slave.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(functions_mutex);
+static struct config_group *functions_group;
+static struct config_group *controllers_group;
+
+struct i3c_slave_func_group {
+	struct config_group group;
+	struct i3c_slave_func *func;
+};
+
+struct i3c_slave_ctrl_group {
+	struct config_group group;
+	struct i3c_slave_ctrl *ctrl;
+};
+
+static inline struct i3c_slave_func_group *to_i3c_slave_func_group(struct config_item *item)
+{
+	return container_of(to_config_group(item), struct i3c_slave_func_group, group);
+}
+
+static inline struct i3c_slave_ctrl_group *to_i3c_slave_ctrl_group(struct config_item *item)
+{
+	return container_of(to_config_group(item), struct i3c_slave_ctrl_group, group);
+}
+
+static int i3c_slave_ctrl_func_link(struct config_item *ctrl_cfg, struct config_item *func_cfg)
+{
+	struct i3c_slave_func_group *func_group = to_i3c_slave_func_group(func_cfg);
+	struct i3c_slave_ctrl_group *ctrl_group = to_i3c_slave_ctrl_group(ctrl_cfg);
+	struct i3c_slave_ctrl *ctrl = ctrl_group->ctrl;
+	struct i3c_slave_func *func = func_group->func;
+	int ret;
+
+	ret = i3c_slave_ctrl_add_func(ctrl, func);
+	if (ret)
+		return ret;
+
+	ret = i3c_slave_func_bind(func);
+	if (ret) {
+		i3c_slave_ctrl_remove_func(ctrl, func);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void i3c_slave_ctrl_func_unlink(struct config_item *ctrl_cfg, struct config_item *func_cfg)
+{
+	struct i3c_slave_func_group *func_group = to_i3c_slave_func_group(func_cfg->ci_parent);
+	struct i3c_slave_ctrl_group *ctrl_group = to_i3c_slave_ctrl_group(ctrl_cfg);
+	struct i3c_slave_ctrl *ctrl = ctrl_group->ctrl;
+	struct i3c_slave_func *func = func_group->func;
+
+	i3c_slave_func_unbind(func);
+	i3c_slave_ctrl_remove_func(ctrl, func);
+}
+
+static ssize_t i3c_slave_ctrl_hotjoin_store(struct config_item *item, const char *page, size_t len)
+{
+	struct i3c_slave_ctrl_group *ctrl_group = to_i3c_slave_ctrl_group(item);
+	struct i3c_slave_ctrl *ctrl;
+	int ret;
+
+	ctrl = ctrl_group->ctrl;
+
+	ret = i3c_slave_ctrl_hotjoin(ctrl);
+	if (ret) {
+		dev_err(&ctrl->dev, "failed to hotjoin i3c slave controller\n");
+		return -EINVAL;
+	}
+
+	return len;
+}
+
+static ssize_t i3c_slave_ctrl_hotjoin_show(struct config_item *item, char *page)
+{
+	return sysfs_emit(page, "%d\n", 0);
+}
+
+CONFIGFS_ATTR(i3c_slave_ctrl_, hotjoin);
+
+static struct configfs_item_operations i3c_slave_ctrl_item_ops = {
+	.allow_link     = i3c_slave_ctrl_func_link,
+	.drop_link      = i3c_slave_ctrl_func_unlink,
+};
+
+static struct configfs_attribute *i3c_slave_ctrl_attrs[] = {
+	&i3c_slave_ctrl_attr_hotjoin,
+	NULL,
+};
+
+static const struct config_item_type i3c_slave_ctrl_type = {
+	.ct_item_ops    = &i3c_slave_ctrl_item_ops,
+	.ct_attrs	= i3c_slave_ctrl_attrs,
+	.ct_owner       = THIS_MODULE,
+};
+
+/**
+ * i3c_slave_cfs_add_ctrl_group() - add I3C slave controller group
+ * @ctrl: I3C slave controller device
+ *
+ * Return: Pointer to struct config_group
+ */
+struct config_group *i3c_slave_cfs_add_ctrl_group(struct i3c_slave_ctrl *ctrl)
+{
+	struct i3c_slave_ctrl_group *ctrl_group;
+	struct config_group *group;
+	int ret;
+
+	ctrl_group = kzalloc(sizeof(*ctrl_group), GFP_KERNEL);
+	if (!ctrl_group) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	group = &ctrl_group->group;
+
+	config_group_init_type_name(group, dev_name(&ctrl->dev), &i3c_slave_ctrl_type);
+	ret = configfs_register_group(controllers_group, group);
+	if (ret) {
+		pr_err("failed to register configfs group for %s\n", dev_name(&ctrl->dev));
+		goto err_register_group;
+	}
+
+	ctrl_group->ctrl = ctrl;
+
+	return group;
+
+err_register_group:
+	kfree(ctrl_group);
+
+err:
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(i3c_slave_cfs_add_ctrl_group);
+
+/**
+ * i3c_slave_cfs_remove_ctrl_group() - remove I3C slave controller group
+ * @group: the group to be removed
+ */
+void i3c_slave_cfs_remove_ctrl_group(struct config_group *group)
+{
+	struct i3c_slave_ctrl_group *ctrl_group;
+
+	if (!group)
+		return;
+
+	ctrl_group = container_of(group, struct i3c_slave_ctrl_group, group);
+	i3c_slave_ctrl_put(ctrl_group->ctrl);
+	configfs_unregister_group(&ctrl_group->group);
+	kfree(ctrl_group);
+}
+EXPORT_SYMBOL(i3c_slave_cfs_remove_ctrl_group);
+
+#define I3C_SLAVE_ATTR_R(_name)                                                \
+static ssize_t i3c_slave_func_##_name##_show(struct config_item *item, char *page)    \
+{                                                                              \
+	struct i3c_slave_func *func = to_i3c_slave_func_group(item)->func;                     \
+	return sysfs_emit(page, "0x%04x\n", func->_name);               \
+}
+
+#define I3C_SLAVE_ATTR_W(_name, _u)                                            \
+static ssize_t i3c_slave_func_##_name##_store(struct config_item *item,               \
+				       const char *page, size_t len)           \
+{                                                                              \
+	_u val;                                                               \
+	struct i3c_slave_func *func = to_i3c_slave_func_group(item)->func;                     \
+	if (kstrto##_u(page, 0, &val) < 0)                                      \
+		return -EINVAL;                                                \
+	func->_name = val;                                              \
+	return len;                                                            \
+}
+
+I3C_SLAVE_ATTR_R(vendor_id);
+I3C_SLAVE_ATTR_W(vendor_id, u16);
+CONFIGFS_ATTR(i3c_slave_func_, vendor_id);
+
+I3C_SLAVE_ATTR_R(vendor_info);
+I3C_SLAVE_ATTR_W(vendor_info, u16);
+CONFIGFS_ATTR(i3c_slave_func_, vendor_info);
+
+I3C_SLAVE_ATTR_R(part_id);
+I3C_SLAVE_ATTR_W(part_id, u16);
+CONFIGFS_ATTR(i3c_slave_func_, part_id);
+
+I3C_SLAVE_ATTR_R(instance_id);
+I3C_SLAVE_ATTR_W(instance_id, u8);
+CONFIGFS_ATTR(i3c_slave_func_, instance_id);
+
+I3C_SLAVE_ATTR_R(ext_id);
+I3C_SLAVE_ATTR_W(ext_id, u16);
+CONFIGFS_ATTR(i3c_slave_func_, ext_id);
+
+I3C_SLAVE_ATTR_R(max_write_len);
+I3C_SLAVE_ATTR_W(max_write_len, u16);
+CONFIGFS_ATTR(i3c_slave_func_, max_write_len);
+
+I3C_SLAVE_ATTR_R(max_read_len);
+I3C_SLAVE_ATTR_W(max_read_len, u16);
+CONFIGFS_ATTR(i3c_slave_func_, max_read_len);
+
+I3C_SLAVE_ATTR_R(bcr);
+I3C_SLAVE_ATTR_W(bcr, u8);
+CONFIGFS_ATTR(i3c_slave_func_, bcr);
+
+I3C_SLAVE_ATTR_R(dcr);
+I3C_SLAVE_ATTR_W(dcr, u8);
+CONFIGFS_ATTR(i3c_slave_func_, dcr);
+
+static struct configfs_attribute *i3c_slave_func_attrs[] = {
+	&i3c_slave_func_attr_vendor_id,
+	&i3c_slave_func_attr_vendor_info,
+	&i3c_slave_func_attr_part_id,
+	&i3c_slave_func_attr_instance_id,
+	&i3c_slave_func_attr_ext_id,
+	&i3c_slave_func_attr_max_write_len,
+	&i3c_slave_func_attr_max_read_len,
+	&i3c_slave_func_attr_bcr,
+	&i3c_slave_func_attr_dcr,
+	NULL,
+};
+
+static const struct config_item_type i3c_slave_func_type = {
+	.ct_attrs       = i3c_slave_func_attrs,
+	.ct_owner       = THIS_MODULE,
+};
+
+static struct config_group *i3c_slave_func_make(struct config_group *group, const char *name)
+{
+	struct i3c_slave_func_group *func_group;
+	struct i3c_slave_func *func;
+	int err;
+
+	func_group = kzalloc(sizeof(*func_group), GFP_KERNEL);
+	if (!func_group)
+		return ERR_PTR(-ENOMEM);
+
+	config_group_init_type_name(&func_group->group, name, &i3c_slave_func_type);
+
+	func = i3c_slave_func_create(group->cg_item.ci_name, name);
+	if (IS_ERR(func)) {
+		pr_err("failed to create i3c slave function device\n");
+		err = -EINVAL;
+		goto free_group;
+	}
+
+	func->group = &func_group->group;
+
+	func_group->func = func;
+
+	return &func_group->group;
+
+free_group:
+	kfree(func_group);
+
+	return ERR_PTR(err);
+}
+
+static void i3c_slave_func_drop(struct config_group *group, struct config_item *item)
+{
+	config_item_put(item);
+}
+
+static struct configfs_group_operations i3c_slave_func_group_ops = {
+	.make_group     = &i3c_slave_func_make,
+	.drop_item      = &i3c_slave_func_drop,
+};
+
+static const struct config_item_type i3c_slave_func_group_type = {
+	.ct_group_ops   = &i3c_slave_func_group_ops,
+	.ct_owner       = THIS_MODULE,
+};
+
+/**
+ * i3c_slave_cfs_add_func_group() - add I3C slave function group
+ * @name: group name
+ *
+ * Return: Pointer to struct config_group
+ */
+struct config_group *i3c_slave_cfs_add_func_group(const char *name)
+{
+	struct config_group *group;
+
+	group = configfs_register_default_group(functions_group, name,
+						&i3c_slave_func_group_type);
+	if (IS_ERR(group))
+		pr_err("failed to register configfs group for %s function\n",
+		       name);
+
+	return group;
+}
+EXPORT_SYMBOL(i3c_slave_cfs_add_func_group);
+
+/**
+ * i3c_slave_cfs_remove_func_group() - add I3C slave function group
+ * @group: group to be removed
+ */
+void i3c_slave_cfs_remove_func_group(struct config_group *group)
+{
+	if (IS_ERR_OR_NULL(group))
+		return;
+
+	configfs_unregister_default_group(group);
+}
+EXPORT_SYMBOL(i3c_slave_cfs_remove_func_group);
+
+static const struct config_item_type i3c_slave_controllers_type = {
+	.ct_owner       = THIS_MODULE,
+};
+
+static const struct config_item_type i3c_slave_functions_type = {
+	.ct_owner       = THIS_MODULE,
+};
+
+static const struct config_item_type i3c_slave_type = {
+	.ct_owner       = THIS_MODULE,
+};
+
+static struct configfs_subsystem i3c_slave_cfs_subsys = {
+	.su_group = {
+		.cg_item = {
+			.ci_namebuf = "i3c_slave",
+			.ci_type = &i3c_slave_type,
+		},
+	},
+	.su_mutex = __MUTEX_INITIALIZER(i3c_slave_cfs_subsys.su_mutex),
+};
+
+static int __init i3c_slave_cfs_init(void)
+{
+	int ret;
+	struct config_group *root = &i3c_slave_cfs_subsys.su_group;
+
+	config_group_init(root);
+
+	ret = configfs_register_subsystem(&i3c_slave_cfs_subsys);
+	if (ret) {
+		pr_err("Error %d while registering subsystem %s\n",
+		       ret, root->cg_item.ci_namebuf);
+		goto err;
+	}
+
+	functions_group = configfs_register_default_group(root, "functions",
+							  &i3c_slave_functions_type);
+	if (IS_ERR(functions_group)) {
+		ret = PTR_ERR(functions_group);
+		pr_err("Error %d while registering functions group\n",
+		       ret);
+		goto err_functions_group;
+	}
+
+	controllers_group =
+		configfs_register_default_group(root, "controllers",
+						&i3c_slave_controllers_type);
+	if (IS_ERR(controllers_group)) {
+		ret = PTR_ERR(controllers_group);
+		pr_err("Error %d while registering controllers group\n",
+		       ret);
+		goto err_controllers_group;
+	}
+
+	return 0;
+
+err_controllers_group:
+	configfs_unregister_default_group(functions_group);
+
+err_functions_group:
+	configfs_unregister_subsystem(&i3c_slave_cfs_subsys);
+
+err:
+	return ret;
+}
+module_init(i3c_slave_cfs_init);
+
+MODULE_DESCRIPTION("I3C FUNC CONFIGFS");
+MODULE_AUTHOR("Frank Li <Frank.Li@nxp.com>");
diff --git a/drivers/i3c/slave.c b/drivers/i3c/slave.c
new file mode 100644
index 0000000000000..4d2cea1d09299
--- /dev/null
+++ b/drivers/i3c/slave.c
@@ -0,0 +1,453 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * configfs to configure the I3C Slave
+ *
+ * Copyright (C) 2023 NXP
+ * Author: Frank Li <Frank.Li@nxp.com>
+ */
+
+#include <linux/configfs.h>
+#include <linux/module.h>
+#include <linux/i3c/slave.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(func_lock);
+static struct class *i3c_slave_ctrl_class;
+
+static void i3c_slave_func_dev_release(struct device *dev)
+{
+	struct i3c_slave_func *func = to_i3c_slave_func(dev);
+
+	kfree(func->name);
+	kfree(func);
+}
+
+static const struct device_type i3c_slave_func_type = {
+	.release        = i3c_slave_func_dev_release,
+};
+
+static int i3c_slave_func_match_driver(struct device *dev, struct device_driver *drv)
+{
+	return !strncmp(dev_name(dev), drv->name, strlen(drv->name));
+}
+
+static int i3c_slave_func_device_probe(struct device *dev)
+{
+	struct i3c_slave_func *func = to_i3c_slave_func(dev);
+	struct i3c_slave_func_driver *driver = to_i3c_slave_func_driver(dev->driver);
+
+	if (!driver->probe)
+		return -ENODEV;
+
+	func->driver = driver;
+
+	return driver->probe(func);
+}
+
+static void i3c_slave_func_device_remove(struct device *dev)
+{
+	struct i3c_slave_func *func = to_i3c_slave_func(dev);
+	struct i3c_slave_func_driver *driver = to_i3c_slave_func_driver(dev->driver);
+
+	if (driver->remove)
+		driver->remove(func);
+	func->driver = NULL;
+}
+
+static const struct bus_type i3c_slave_func_bus_type = {
+	.name = "i3c_slave_func",
+	.probe = i3c_slave_func_device_probe,
+	.remove = i3c_slave_func_device_remove,
+	.match = i3c_slave_func_match_driver,
+};
+
+static void i3c_slave_ctrl_release(struct device *dev)
+{
+	kfree(to_i3c_slave_ctrl(dev));
+}
+
+static void devm_i3c_slave_ctrl_release(struct device *dev, void *res)
+{
+	struct i3c_slave_ctrl *ctrl = *(struct i3c_slave_ctrl **)res;
+
+	i3c_slave_ctrl_destroy(ctrl);
+}
+
+struct i3c_slave_ctrl *
+__devm_i3c_slave_ctrl_create(struct device *dev, const struct i3c_slave_ctrl_ops *ops,
+			     struct module *owner)
+{
+	struct i3c_slave_ctrl **ptr, *ctrl;
+
+	ptr = devres_alloc(devm_i3c_slave_ctrl_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	ctrl = __i3c_slave_ctrl_create(dev, ops, owner);
+	if (!IS_ERR(ctrl)) {
+		*ptr = ctrl;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return ctrl;
+}
+
+static int devm_i3c_slave_ctrl_match(struct device *dev, void *res, void *match_data)
+{
+	struct i3c_slave_ctrl **ptr = res;
+
+	return *ptr == match_data;
+}
+
+/**
+ * __i3c_slave_ctrl_create() - create a new slave controller device
+ * @dev: device that is creating the new slave controller
+ * @ops: function pointers for performing slave controller  operations
+ * @owner: the owner of the module that creates the slave controller device
+ *
+ * Return: Pointer to struct i3c_slave_ctrl
+ */
+struct i3c_slave_ctrl *
+__i3c_slave_ctrl_create(struct device *dev, const struct i3c_slave_ctrl_ops *ops,
+			struct module *owner)
+{
+	struct i3c_slave_ctrl *ctrl;
+	int ret;
+
+	if (WARN_ON(!dev))
+		return ERR_PTR(-EINVAL);
+
+	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return ERR_PTR(-ENOMEM);
+
+	device_initialize(&ctrl->dev);
+	ctrl->dev.class = i3c_slave_ctrl_class;
+	ctrl->dev.parent = dev;
+	ctrl->dev.release = i3c_slave_ctrl_release;
+	ctrl->ops = ops;
+
+	ret = dev_set_name(&ctrl->dev, "%s", dev_name(dev));
+	if (ret)
+		goto put_dev;
+
+	ret = device_add(&ctrl->dev);
+	if (ret)
+		goto put_dev;
+
+	ctrl->group = i3c_slave_cfs_add_ctrl_group(ctrl);
+	if (!ctrl->group)
+		goto put_dev;
+
+	return ctrl;
+
+put_dev:
+	put_device(&ctrl->dev);
+	kfree(ctrl);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(__i3c_slave_ctrl_create);
+
+/**
+ * devm_i3c_slave_ctrl_destroy() - destroy the slave controller device
+ * @dev: device that is creating the new slave controller device
+ * @ops: function pointers for performing slave controller operations
+ * @owner: the owner of the module that creates the slave controller device
+ *
+ * Invoke to create a new slave controller device and add it to i3c_slave class. While at that, it
+ * also associates the device with the i3c_slave using devres. On driver detach, release function is
+ * invoked on the devres data, then devres data is freed.
+ */
+void devm_i3c_slave_ctrl_destroy(struct device *dev, struct i3c_slave_ctrl *ctrl)
+{
+	int r;
+
+	r = devres_destroy(dev, devm_i3c_slave_ctrl_release, devm_i3c_slave_ctrl_match,
+			   ctrl);
+	dev_WARN_ONCE(dev, r, "couldn't find I3C controller resource\n");
+}
+EXPORT_SYMBOL_GPL(devm_i3c_slave_ctrl_destroy);
+
+/**
+ * i3c_slave_ctrl_destroy() - destroy the slave controller device
+ * @ctrl: the slave controller device that has to be destroyed
+ *
+ * Invoke to destroy the I3C slave device
+ */
+void i3c_slave_ctrl_destroy(struct i3c_slave_ctrl *ctrl)
+{
+	i3c_slave_cfs_remove_ctrl_group(ctrl->group);
+	device_unregister(&ctrl->dev);
+}
+EXPORT_SYMBOL_GPL(i3c_slave_ctrl_destroy);
+
+/**
+ * i3c_slave_ctrl_add_func() - bind I3C slave function to an slave controller
+ * @ctrl: the controller device to which the slave function should be added
+ * @func: the slave function to be added
+ *
+ * An I3C slave device can have only one functions.
+ */
+int i3c_slave_ctrl_add_func(struct i3c_slave_ctrl *ctrl, struct i3c_slave_func *func)
+{
+	if (ctrl->func)
+		return -EBUSY;
+
+	ctrl->func = func;
+	func->ctrl = ctrl;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(i3c_slave_ctrl_add_func);
+
+/**
+ * i3c_slave_ctrl_remove_func() - unbind I3C slave function to an slave controller
+ * @ctrl: the controller device to which the slave function should be removed
+ * @func: the slave function to be removed
+ *
+ * An I3C slave device can have only one functions.
+ */
+void i3c_slave_ctrl_remove_func(struct i3c_slave_ctrl *ctrl, struct i3c_slave_func *func)
+{
+	ctrl->func = NULL;
+}
+EXPORT_SYMBOL_GPL(i3c_slave_ctrl_remove_func);
+
+/**
+ * i3c_slave_ctrl() - get the I3C slave controller
+ * @name: device name of the slave controller
+ *
+ * Invoke to get struct i3c_slave_ctrl * corresponding to the device name of the
+ * slave controller
+ */
+struct i3c_slave_ctrl *i3c_slave_ctrl_get(const char *name)
+{
+	int ret = -EINVAL;
+	struct i3c_slave_ctrl *ctrl;
+	struct device *dev;
+	struct class_dev_iter iter;
+
+	class_dev_iter_init(&iter, i3c_slave_ctrl_class, NULL, NULL);
+	while ((dev = class_dev_iter_next(&iter))) {
+		if (strcmp(name, dev_name(dev)))
+			continue;
+
+		ctrl = to_i3c_slave_ctrl(dev);
+		if (!try_module_get(ctrl->ops->owner)) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		class_dev_iter_exit(&iter);
+		get_device(&ctrl->dev);
+		return ctrl;
+	}
+
+err:
+	class_dev_iter_exit(&iter);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(i3c_slave_ctrl_get);
+
+/**
+ * i3c_slave_ctrl_put() - release the I3C endpoint controller
+ * @ctrl: slave controller returned by pci_slave_get()
+ *
+ * release the refcount the caller obtained by invoking i3c_slave_ctrl_get()
+ */
+void i3c_slave_ctrl_put(struct i3c_slave_ctrl *ctrl)
+{
+	if (!ctrl || IS_ERR(ctrl))
+		return;
+
+	module_put(ctrl->ops->owner);
+	put_device(&ctrl->dev);
+}
+EXPORT_SYMBOL_GPL(i3c_slave_ctrl_put);
+
+/**
+ * i3c_slave_ctrl_hotjoin() - trigger device hotjoin
+ * @ctrl:  slave controller
+ *
+ * return: 0: success, others failure
+ */
+int i3c_slave_ctrl_hotjoin(struct i3c_slave_ctrl *ctrl)
+{
+	if (!ctrl || IS_ERR(ctrl))
+		return -EINVAL;
+
+	if (!ctrl->ops->hotjoin)
+		return -EINVAL;
+
+	return ctrl->ops->hotjoin(ctrl);
+}
+EXPORT_SYMBOL_GPL(i3c_slave_ctrl_hotjoin);
+
+/**
+ * i3c_slave_func_bind() - Notify the function driver that the function device has been bound to a
+ *			   controller device
+ * @func: the function device which has been bound to the controller device
+ *
+ * Invoke to notify the function driver that it has been bound to a controller device
+ */
+int i3c_slave_func_bind(struct i3c_slave_func *func)
+{
+	struct device *dev = &func->dev;
+	int ret;
+
+	if (!func->driver) {
+		dev_WARN(dev, "func device not bound to driver\n");
+		return -EINVAL;
+	}
+
+	if (!try_module_get(func->driver->owner))
+		return -EAGAIN;
+
+	mutex_lock(&func->lock);
+	ret = func->driver->ops->bind(func);
+	if (!ret)
+		func->is_bound = true;
+	mutex_unlock(&func->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_slave_func_bind);
+
+/**
+ * i3c_slave_func_unbind() - Notify the function driver that the binding between the function device
+ *			     and controller device has been lost
+ * @func: the function device which has lost the binding with the controller device
+ *
+ * Invoke to notify the function driver that the binding between the function device and controller
+ * device has been lost.
+ */
+void i3c_slave_func_unbind(struct i3c_slave_func *func)
+{
+	if (!func->driver) {
+		dev_WARN(&func->dev, "func device not bound to driver\n");
+		return;
+	}
+
+	mutex_lock(&func->lock);
+	if (func->is_bound)
+		func->driver->ops->unbind(func);
+	mutex_unlock(&func->lock);
+
+	module_put(func->driver->owner);
+}
+EXPORT_SYMBOL_GPL(i3c_slave_func_unbind);
+
+/**
+ * i3c_slave_func_create() - create a new I3C function device
+ * @drv_name: the driver name of the I3C function device.
+ * @name: the name of the function device.
+ *
+ * Invoke to create a new I3C function device by providing the name of the function device.
+ */
+struct i3c_slave_func *i3c_slave_func_create(const char *drv_name, const char *name)
+{
+	struct i3c_slave_func *func;
+	struct device *dev;
+	int ret;
+
+	func = kzalloc(sizeof(*func), GFP_KERNEL);
+	if (!func)
+		return ERR_PTR(-ENOMEM);
+
+	dev = &func->dev;
+	device_initialize(dev);
+	dev->bus = &i3c_slave_func_bus_type;
+	dev->type = &i3c_slave_func_type;
+	mutex_init(&func->lock);
+
+	ret = dev_set_name(dev, "%s.%s", drv_name, name);
+	if (ret) {
+		put_device(dev);
+		return ERR_PTR(ret);
+	}
+
+	ret = device_add(dev);
+	if (ret) {
+		put_device(dev);
+		return ERR_PTR(ret);
+	}
+
+	return func;
+}
+EXPORT_SYMBOL_GPL(i3c_slave_func_create);
+
+/**
+ * __i3c_slave_func_register_driver() - register a new I3C function driver
+ * @driver: structure representing I3C function driver
+ * @owner: the owner of the module that registers the I3C function driver
+ *
+ * Invoke to register a new I3C function driver.
+ */
+int __i3c_slave_func_register_driver(struct i3c_slave_func_driver *driver, struct module *owner)
+{
+	int ret = -EEXIST;
+
+	if (!driver->ops)
+		return -EINVAL;
+
+	if (!driver->ops->bind || !driver->ops->unbind)
+		return -EINVAL;
+
+	driver->driver.bus = &i3c_slave_func_bus_type;
+	driver->driver.owner = owner;
+
+	ret = driver_register(&driver->driver);
+	if (ret)
+		return ret;
+
+	i3c_slave_cfs_add_func_group(driver->driver.name);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__i3c_slave_func_register_driver);
+
+/**
+ * i3c_slave_func_unregister_driver() - unregister the I3C function driver
+ * @driver: the I3C function driver that has to be unregistered
+ *
+ * Invoke to unregister the I3C function driver.
+ */
+void i3c_slave_func_unregister_driver(struct i3c_slave_func_driver *fd)
+{
+	mutex_lock(&func_lock);
+	mutex_unlock(&func_lock);
+}
+EXPORT_SYMBOL_GPL(i3c_slave_func_unregister_driver);
+
+static int __init i3c_slave_init(void)
+{
+	int ret;
+
+	i3c_slave_ctrl_class = class_create("i3c_slave");
+	if (IS_ERR(i3c_slave_ctrl_class)) {
+		pr_err("failed to create i3c slave class --> %ld\n", PTR_ERR(i3c_slave_ctrl_class));
+		return PTR_ERR(i3c_slave_ctrl_class);
+	}
+
+	ret = bus_register(&i3c_slave_func_bus_type);
+	if (ret) {
+		class_destroy(i3c_slave_ctrl_class);
+		pr_err("failed to register i3c slave func bus --> %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+module_init(i3c_slave_init);
+
+static void __exit i3c_slave_exit(void)
+{
+	class_destroy(i3c_slave_ctrl_class);
+	bus_unregister(&i3c_slave_func_bus_type);
+}
+module_exit(i3c_slave_exit);
+
diff --git a/include/linux/i3c/slave.h b/include/linux/i3c/slave.h
new file mode 100644
index 0000000000000..19eb71cfa81f2
--- /dev/null
+++ b/include/linux/i3c/slave.h
@@ -0,0 +1,503 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2023 NXP.
+ *
+ * Author: Frank Li <Frank.Li@nxp.com>
+ */
+
+#ifndef I3C_SLAVE_H
+#define I3C_SLAVE_H
+
+#include <linux/device.h>
+
+struct i3c_slave_func;
+struct i3c_slave_ctrl;
+
+/**
+ * struct i3c_slave_func_ops - set of function pointers for performing i3c slave function operations
+ * @bind: ops to perform when a controller device has been bound to function device
+ * @unbind: ops to perform when a binding has been lost between a controller device and function
+ *	    device
+ */
+struct i3c_slave_func_ops {
+	int (*bind)(struct i3c_slave_func *func);
+	void (*unbind)(struct i3c_slave_func *func);
+};
+
+/**
+ * struct i3c_slave_func_driver - represents the I3C function driver
+ * @probe: ops to perform when a new function device has been bound to the function driver
+ * @remove: ops to perform when the binding between the function device and function driver is
+ *	    broken
+ * @driver: I3C Function driver
+ * @ops: set of function pointers for performing function operations
+ * @owner: the owner of the module that registers the I3C function driver
+ * @epf_group: list of configfs group corresponding to the I3C function driver
+ */
+struct i3c_slave_func_driver {
+	int (*probe)(struct i3c_slave_func *func);
+	void (*remove)(struct i3c_slave_func *func);
+
+	char *name;
+	struct device_driver driver;
+	struct i3c_slave_func_ops *ops;
+	struct module *owner;
+};
+
+/**
+ * struct i3c_slave_func - represents the I3C function device
+ * @dev: the I3C function device
+ * @name: the name of the I3C function device
+ * @driver: the function driver to which this function device is bound
+ * @group: configfs group associated with the EPF device
+ * @lock: mutex to protect i3c_slave_func_ops
+ * @ctrl: binded I3C controller device
+ * @is_bound: indicates if bind notification to function driver has been invoked
+ * @vednor_id: vendor id
+ * @part_id: part id
+ * @instance_id: instance id
+ * @ext_id: ext id
+ * @vendor_info: vendor info
+ * @static_addr: static address for I2C. It is 0 for I3C.
+ * @max_write_len: maximum write length
+ * @max_read_len: maximum read length
+ * @bcr: bus characteristics register (BCR)
+ * @dcr: device characteristics register (DCR)
+ */
+struct i3c_slave_func {
+	struct device dev;
+	char *name;
+	struct i3c_slave_func_driver *driver;
+	struct config_group *group;
+	/* mutex to protect against concurrent access of i3c_slave_func_ops */
+	struct mutex lock;
+	struct i3c_slave_ctrl *ctrl;
+	bool is_bound;
+
+	u16 vendor_id;
+	u16 part_id;
+	u8 instance_id;
+	u16 ext_id;
+	u8 vendor_info;
+	u16 static_addr;
+	u16 max_write_len;	//0 is hardware default max value
+	u16 max_read_len;	//0 is hardware default max value
+	u8 bcr;
+	u8 dcr;
+};
+
+enum i3c_request_stat {
+	I3C_REQUEST_OKAY,
+	I3C_REQUEST_PARTIAL,
+	I3C_REQUEST_ERR,
+	I3C_REQUEST_CANCEL,
+};
+
+/**
+ * struct i3c_request - represents the an I3C transfer request
+ * @buf: data buffer
+ * @length: data length
+ * @complete: call back function when request finished or cancelled
+ * @context: general data for complete callback function
+ * @status: transfer status
+ * @actual: how much actually transferred
+ * @ctrl: I3C slave controller associate with this request
+ * @tx: transfer direction, 1: slave to master, 0: master to slave
+ */
+struct i3c_request {
+	void *buf;
+	unsigned int length;
+
+	void (*complete)(struct i3c_request *req);
+	void *context;
+	struct list_head list;
+
+	enum i3c_request_stat status;
+	unsigned int actual;
+	struct i3c_slave_ctrl *ctrl;
+	bool tx;
+};
+
+/**
+ * struct i3c_slave_ctrl_features - represents I3C slave controller features.
+ * @tx_fifo_sz: tx hardware fifo size
+ * @rx_fifo_sz: rx hardware fifo size
+ */
+struct i3c_slave_ctrl_features {
+	u32 tx_fifo_sz;
+	u32 rx_fifo_sz;
+};
+
+/**
+ * struct i3c_slave_ctrl_ops - set of function pointers for performing controller operations
+ * @set_config: set I3C controller configuration
+ * @enable: enable I3C controller
+ * @disable: disable I3C controller
+ * @raise_ibi: rasie IBI interrupt to master
+ * @queue: queue an I3C transfer
+ * @dequeue: dequeue an I3C transfer
+ * @cancel_all_reqs: call all pending requests
+ * @fifo_status: current FIFO status
+ * @fifo_flush: flush hardware FIFO
+ * @get_features: ops to get the features supported by the I3C slave controller
+ * @owner: the module owner containing the ops
+ */
+struct i3c_slave_ctrl_ops {
+	int (*set_config)(struct i3c_slave_ctrl *ctrl, struct i3c_slave_func *func);
+	int (*enable)(struct i3c_slave_ctrl *ctrl);
+	int (*disable)(struct i3c_slave_ctrl *ctrl);
+	int (*raise_ibi)(struct i3c_slave_ctrl *ctrl, void *p, u8 size);
+
+	struct i3c_request *(*alloc_request)(struct i3c_slave_ctrl *ctrl, gfp_t gfp_flags);
+	void (*free_request)(struct i3c_request *req);
+
+	int (*queue)(struct i3c_request *req, gfp_t gfp_flags);
+	int (*dequeue)(struct i3c_request *req);
+
+	void (*cancel_all_reqs)(struct i3c_slave_ctrl *ctrl, bool tx);
+
+	int (*fifo_status)(struct i3c_slave_ctrl *ctrl, bool tx);
+	void (*fifo_flush)(struct i3c_slave_ctrl *ctrl, bool tx);
+	int (*hotjoin)(struct i3c_slave_ctrl *ctrl);
+	int (*set_status_format1)(struct i3c_slave_ctrl *ctrl, u16 status);
+	u16 (*get_status_format1)(struct i3c_slave_ctrl *ctrl);
+	u8  (*get_addr)(struct i3c_slave_ctrl *ctrl);
+	const struct i3c_slave_ctrl_features *(*get_features)(struct i3c_slave_ctrl *ctrl);
+	struct module *owner;
+};
+
+/**
+ * struct i3c_slave_ctrl - represents the I3C slave device
+ * @dev: I3C slave device
+ * @ops: function pointers for performing endpoint operations
+ * @func: slave functions present in this controller device
+ * @group: configfs group representing the I3C controller device
+ */
+struct i3c_slave_ctrl {
+	struct device dev;
+	const struct i3c_slave_ctrl_ops *ops;
+	struct i3c_slave_func *func;
+	struct config_group *group;
+};
+
+/**
+ * i3c_slave_ctrl_raise_ibi() - Raise IBI to master
+ * @ctrl: I3C slave controller
+ * @p: optional data for IBI
+ * @size: size of optional data
+ *
+ * Returns: Zero for success, or an error code in case of failure
+ */
+static inline int i3c_slave_ctrl_raise_ibi(struct i3c_slave_ctrl *ctrl, void *p, u8 size)
+{
+	if (ctrl && ctrl->ops && ctrl->ops->raise_ibi)
+		return ctrl->ops->raise_ibi(ctrl, p, size);
+
+	return -EINVAL;
+}
+
+/**
+ * i3c_slave_ctrl_cancel_all_reqs() - Cancel all pending request
+ * @ctrl: I3C slave controller
+ * @tx: Transfer diretion queue
+ * @size: size of optional data
+ */
+static inline void i3c_slave_ctrl_cancel_all_reqs(struct i3c_slave_ctrl *ctrl, bool tx)
+{
+	if (ctrl && ctrl->ops && ctrl->ops->cancel_all_reqs)
+		ctrl->ops->cancel_all_reqs(ctrl, tx);
+}
+
+/**
+ * i3c_slave_ctrl_set_config() - Set controller configuration
+ * @ctrl: I3C slave controller device
+ * @func: Function device
+ *
+ * Returns: Zero for success, or an error code in case of failure
+ */
+static inline int
+i3c_slave_ctrl_set_config(struct i3c_slave_ctrl *ctrl, struct i3c_slave_func *func)
+{
+	if (ctrl && ctrl->ops && ctrl->ops->set_config)
+		return ctrl->ops->set_config(ctrl, func);
+
+	return -EINVAL;
+}
+
+/**
+ * i3c_slave_ctrl_enable() - Enable I3C controller
+ * @ctrl: I3C slave controller device
+ *
+ * Returns: Zero for success, or an error code in case of failure
+ */
+static inline int
+i3c_slave_ctrl_enable(struct i3c_slave_ctrl *ctrl)
+{
+	if (ctrl && ctrl->ops && ctrl->ops->enable)
+		return ctrl->ops->enable(ctrl);
+
+	return -EINVAL;
+}
+
+/**
+ * i3c_slave_ctrl_disable() - Disable I3C controller
+ * @ctrl: I3C slave controller device
+ *
+ * Returns: Zero for success, or an error code in case of failure
+ */
+static inline int
+i3c_slave_ctrl_disable(struct i3c_slave_ctrl *ctrl)
+{
+	if (ctrl && ctrl->ops && ctrl->ops->disable)
+		return ctrl->ops->disable(ctrl);
+
+	return -EINVAL;
+}
+
+/**
+ * i3c_slave_ctrl_alloc_request() - Alloc an I3C transfer
+ * @ctrl: I3C slave controller device
+ * gfp_flags: additional gfp flags used when allocating the buffers
+ *
+ * Returns: Zero for success, or an error code in case of failure
+ */
+static inline struct i3c_request *
+i3c_slave_ctrl_alloc_request(struct i3c_slave_ctrl *ctrl, gfp_t gfp_flags)
+{
+	struct i3c_request *req = NULL;
+
+	if (ctrl && ctrl->ops && ctrl->ops->alloc_request)
+		req = ctrl->ops->alloc_request(ctrl, gfp_flags);
+	else
+		req = kzalloc(sizeof(*req), gfp_flags);
+
+	if (req)
+		req->ctrl = ctrl;
+
+	return req;
+}
+
+/**
+ * i3c_slave_ctrl_free_request() - Free an I3C transfer
+ * @ctrl: I3C slave controller device
+ *
+ * Returns: Zero for success, or an error code in case of failure
+ */
+static inline void
+i3c_slave_ctrl_free_request(struct i3c_request *req)
+{
+	struct i3c_slave_ctrl *ctrl;
+
+	if (!req)
+		return;
+
+	ctrl = req->ctrl;
+	if (ctrl && ctrl->ops && ctrl->ops->free_request)
+		ctrl->ops->free_request(req);
+	else
+		kfree(req);
+}
+
+/**
+ * i3c_slave_ctrl_queue() - Queue an I3C transfer
+ * @ctrl: I3C slave controller device
+ * gfp_flags: additional gfp flags used when allocating the buffers
+ *
+ * Returns: Zero for success, or an error code in case of failure
+ */
+static inline int
+i3c_slave_ctrl_queue(struct i3c_request *req, gfp_t gfp_flags)
+{
+	struct i3c_slave_ctrl *ctrl;
+	int ret = -EINVAL;
+
+	if (!req)
+		return -EINVAL;
+
+	ctrl = req->ctrl;
+
+	req->actual = 0;
+	req->status = 0;
+	if (ctrl && ctrl->ops && ctrl->ops->queue)
+		ret = ctrl->ops->queue(req, gfp_flags);
+
+	return ret;
+}
+
+/**
+ * i3c_slave_ctrl_dequeue() - Dequeue an I3C transfer
+ * @ctrl: I3C slave controller device
+ *
+ * Returns: Zero for success, or an error code in case of failure
+ */
+static inline int
+i3c_slave_ctrl_dequeue(struct i3c_request *req)
+{
+	struct i3c_slave_ctrl *ctrl;
+	int ret = -EINVAL;
+
+	if (!req)
+		return -EINVAL;
+
+	ctrl = req->ctrl;
+	if (ctrl && ctrl->ops && ctrl->ops->dequeue)
+		ret = ctrl->ops->dequeue(req);
+
+	return ret;
+}
+
+/**
+ * i3c_slave_ctrl_fifo_status() - Get controller FIFO status
+ * @ctrl: I3C slave controller device
+ * @tx: 1: Slave to master, 0: master to slave
+ *
+ * Returns: How much data in FIFO
+ */
+static inline int
+i3c_slave_ctrl_fifo_status(struct i3c_slave_ctrl *ctrl, bool tx)
+{
+	if (ctrl && ctrl->ops && ctrl->ops->fifo_status)
+		return ctrl->ops->fifo_status(ctrl, tx);
+
+	return 0;
+}
+
+/**
+ * i3c_slave_ctrl_fifo_flush() - Flush controller FIFO
+ * @ctrl: I3C slave controller device
+ * @tx: 1: Slave to master, 0: master to slave
+ *
+ */
+static inline void
+i3c_slave_ctrl_fifo_flush(struct i3c_slave_ctrl *ctrl, bool tx)
+{
+	if (ctrl && ctrl->ops && ctrl->ops->fifo_flush)
+		return ctrl->ops->fifo_flush(ctrl, tx);
+}
+
+/**
+ * i3c_slave_ctrl_get_features() - Get controller supported features
+ * @ctrl: I3C slave controller device
+ *
+ * Returns: The pointer to struct i3c_slave_ctrl_features
+ */
+static inline const struct i3c_slave_ctrl_features*
+i3c_slave_ctrl_get_features(struct i3c_slave_ctrl *ctrl)
+{
+	if (ctrl && ctrl->ops && ctrl->ops->get_features)
+		return ctrl->ops->get_features(ctrl);
+
+	return NULL;
+}
+
+/**
+ * i3c_slave_set_status_format1() - Set controller supported features
+ * &ctrl: I3C slave controller device
+ * &status: I3C GETSTATUS format1
+ *
+ * Returns: Zero for success, or an error code in case of failure
+ */
+static inline int
+i3c_slave_ctrl_set_status_format1(struct i3c_slave_ctrl *ctrl, u16 status)
+{
+	if (ctrl && ctrl->ops && ctrl->ops->set_status_format1)
+		return ctrl->ops->set_status_format1(ctrl, status);
+
+	return -EINVAL;
+}
+
+/**
+ * i3c_slave_get_status_format1() - Get controller supported features
+ * &ctrl: I3C slave controller device
+ *
+ * Return: I3C GETSTATUS format1
+ */
+static inline u16
+i3c_slave_ctrl_get_status_format1(struct i3c_slave_ctrl *ctrl)
+{
+	if (ctrl && ctrl->ops && ctrl->ops->get_status_format1)
+		return ctrl->ops->get_status_format1(ctrl);
+
+	return 0;
+}
+
+/**
+ * i3c_slave_ctrl_get_addr() - Get controller address
+ * &ctrl: I3C slave controller device
+ *
+ * Return: address
+ */
+static inline u8 i3c_slave_ctrl_get_addr(struct i3c_slave_ctrl *ctrl)
+{
+	if (ctrl && ctrl->ops && ctrl->ops->get_addr)
+		return ctrl->ops->get_addr(ctrl);
+
+	return 0;
+}
+
+#define to_i3c_slave_ctrl(device) container_of((device), struct i3c_slave_ctrl, dev)
+
+#define to_i3c_slave_func(func_dev) container_of((func_dev), struct i3c_slave_func, dev)
+#define to_i3c_slave_func_driver(drv) (container_of((drv), struct i3c_slave_func_driver, driver))
+
+#define i3c_slave_ctrl_create(dev, ops) \
+		__i3c_slave_ctrl_create((dev), (ops), THIS_MODULE)
+#define devm_i3c_slave_ctrl_create(dev, ops) \
+		__devm_i3c_slave_ctrl_create((dev), (ops), THIS_MODULE)
+
+struct i3c_slave_ctrl *
+__devm_i3c_slave_ctrl_create(struct device *dev, const struct i3c_slave_ctrl_ops *ops,
+			     struct module *owner);
+struct i3c_slave_ctrl *
+__i3c_slave_ctrl_create(struct device *dev, const struct i3c_slave_ctrl_ops *ops,
+			struct module *owner);
+
+void devm_i3c_slave_ctrl_destroy(struct device *dev, struct i3c_slave_ctrl *epc);
+void i3c_slave_ctrl_destroy(struct i3c_slave_ctrl *epc);
+
+int i3c_slave_ctrl_add_func(struct i3c_slave_ctrl *ctrl, struct i3c_slave_func *func);
+void i3c_slave_ctrl_remove_func(struct i3c_slave_ctrl *ctrl, struct i3c_slave_func *func);
+int i3c_slave_ctrl_hotjoin(struct i3c_slave_ctrl *ctrl);
+
+struct config_group *i3c_slave_cfs_add_ctrl_group(struct i3c_slave_ctrl *ctrl);
+
+void i3c_slave_cfs_remove_ctrl_group(struct config_group *group);
+struct config_group *i3c_slave_cfs_add_func_group(const char *name);
+void i3c_slave_cfs_remove_func_group(struct config_group *group);
+struct i3c_slave_ctrl *i3c_slave_ctrl_get(const char *name);
+void i3c_slave_ctrl_put(struct i3c_slave_ctrl *ctrl);
+
+int i3c_slave_func_bind(struct i3c_slave_func *func);
+void i3c_slave_func_unbind(struct i3c_slave_func *func);
+struct i3c_slave_func *i3c_slave_func_create(const char *drv_name, const char *name);
+
+#define i3c_slave_func_register_driver(drv) \
+	__i3c_slave_func_register_driver(drv, THIS_MODULE)
+
+int __i3c_slave_func_register_driver(struct i3c_slave_func_driver *drv, struct module *owner);
+void i3c_slave_func_unregister_driver(struct i3c_slave_func_driver *drv);
+
+#define DECLARE_I3C_SLAVE_FUNC(_name, _probe, _remove, _ops)			\
+	static struct i3c_slave_func_driver _name ## i3c_func = {		\
+		.driver.name = __stringify(_name),				\
+		.owner  = THIS_MODULE,						\
+		.probe = _probe,						\
+		.remove = _remove,						\
+		.ops = _ops							\
+	};									\
+	MODULE_ALIAS("i3cfunc:" __stringify(_name))
+
+#define DECLARE_I3C_SLAVE_INIT(_name, _probe, _remove, _ops)			\
+	DECLARE_I3C_SLAVE_FUNC(_name, _probe, _remove, _ops);			\
+	static int __init _name ## mod_init(void)				\
+	{									\
+		return i3c_slave_func_register_driver(&_name ## i3c_func);	\
+	}									\
+	static void __exit _name ## mod_exit(void)				\
+	{									\
+		i3c_slave_func_unregister_driver(&_name ## i3c_func);		\
+	}									\
+	module_init(_name ## mod_init);						\
+	module_exit(_name ## mod_exit)
+
+#endif
-- 
2.34.1


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

* [PATCH 2/5] dt-bindings: i3c: svc: add compatible string i3c: silvaco,i3c-slave
  2023-10-18 21:58 [PATCH 0/5] I3C slave mode support Frank Li
  2023-10-18 21:58 ` [PATCH 1/5] i3c: add " Frank Li
@ 2023-10-18 21:58 ` Frank Li
  2023-10-19  7:00   ` Krzysztof Kozlowski
  2023-10-19 12:07   ` Rob Herring
  2023-10-18 21:58 ` [PATCH 3/5] i3c: slave: add svc slave controller support Frank Li
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 17+ messages in thread
From: Frank Li @ 2023-10-18 21:58 UTC (permalink / raw)
  To: miquel.raynal, conor.culhane, alexandre.belloni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, joe, Frank.Li,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: gregkh, imx, jirislaby, linux-serial

Add compatible string 'silvaco,i3c-slave' for slave mode.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 .../devicetree/bindings/i3c/silvaco,i3c-master.yaml       | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml
index 133855f11b4f5..63db63f00a509 100644
--- a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml
+++ b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml
@@ -4,7 +4,7 @@
 $id: http://devicetree.org/schemas/i3c/silvaco,i3c-master.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Silvaco I3C master
+title: Silvaco I3C master/slave
 
 maintainers:
   - Conor Culhane <conor.culhane@silvaco.com>
@@ -14,8 +14,10 @@ allOf:
 
 properties:
   compatible:
-    const: silvaco,i3c-master-v1
-
+    const:
+      enum:
+        - silvaco,i3c-master-v1
+        - silvaco,i3c-slave-v1
   reg:
     maxItems: 1
 
-- 
2.34.1


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

* [PATCH 3/5] i3c: slave: add svc slave controller support
  2023-10-18 21:58 [PATCH 0/5] I3C slave mode support Frank Li
  2023-10-18 21:58 ` [PATCH 1/5] i3c: add " Frank Li
  2023-10-18 21:58 ` [PATCH 2/5] dt-bindings: i3c: svc: add compatible string i3c: silvaco,i3c-slave Frank Li
@ 2023-10-18 21:58 ` Frank Li
  2023-10-23  1:29   ` kernel test robot
  2023-10-18 21:58 ` [PATCH 4/5] i3c: slave: func: add tty driver Frank Li
  2023-10-18 21:58 ` [PATCH 5/5] Documentation: i3c: Add I3C slave mode controller and function Frank Li
  4 siblings, 1 reply; 17+ messages in thread
From: Frank Li @ 2023-10-18 21:58 UTC (permalink / raw)
  To: miquel.raynal, conor.culhane, alexandre.belloni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, joe, Frank.Li,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: gregkh, imx, jirislaby, linux-serial

Add Silvaco I3C slave controller support

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 drivers/i3c/Kconfig               |   3 +
 drivers/i3c/Makefile              |   1 +
 drivers/i3c/slave/Kconfig         |   9 +
 drivers/i3c/slave/Makefile        |   4 +
 drivers/i3c/slave/svc-i3c-slave.c | 795 ++++++++++++++++++++++++++++++
 5 files changed, 812 insertions(+)
 create mode 100644 drivers/i3c/slave/Kconfig
 create mode 100644 drivers/i3c/slave/Makefile
 create mode 100644 drivers/i3c/slave/svc-i3c-slave.c

diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig
index d5f5ca7cd6a56..802a9b3576f13 100644
--- a/drivers/i3c/Kconfig
+++ b/drivers/i3c/Kconfig
@@ -48,3 +48,6 @@ config I3C_SLAVE_CONFIGFS
 	  the slave function and used to bind the function with a slave
 	  controller.
 
+if I3C_SLAVE
+source "drivers/i3c/slave/Kconfig"
+endif # I3C_SLAVE
diff --git a/drivers/i3c/Makefile b/drivers/i3c/Makefile
index 6407ddec3a4a9..ef1acbe13fe60 100644
--- a/drivers/i3c/Makefile
+++ b/drivers/i3c/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_I3C)		+= i3c.o
 obj-$(CONFIG_I3C)		+= master/
 obj-$(CONFIG_I3C_SLAVE)		+= slave.o
 obj-$(CONFIG_I3C_SLAVE_CONFIGFS)	+= i3c-cfs.o
+obj-$(CONFIG_I3C_SLAVE)		+= slave/
diff --git a/drivers/i3c/slave/Kconfig b/drivers/i3c/slave/Kconfig
new file mode 100644
index 0000000000000..e385dbdea193b
--- /dev/null
+++ b/drivers/i3c/slave/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config I3C_SLAVE_CTRL_SVC
+	tristate "Silvaco I3C Dual-Role Slave driver"
+	depends on I3C
+	depends on HAS_IOMEM
+	depends on !(ALPHA || PARISC)
+	help
+	  Support for Silvaco I3C Dual-Role Slave Controller.
diff --git a/drivers/i3c/slave/Makefile b/drivers/i3c/slave/Makefile
new file mode 100644
index 0000000000000..612be24536311
--- /dev/null
+++ b/drivers/i3c/slave/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-${CONFIG_I3C_SLAVE_CTRL_SVC} += svc-i3c-slave.o
+
diff --git a/drivers/i3c/slave/svc-i3c-slave.c b/drivers/i3c/slave/svc-i3c-slave.c
new file mode 100644
index 0000000000000..2de741a9e0ff8
--- /dev/null
+++ b/drivers/i3c/slave/svc-i3c-slave.c
@@ -0,0 +1,795 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2023 NXP.
+ *
+ * Author: Frank Li <Frank.Li@nxp.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/i3c/slave.h>
+#include <linux/i3c/slave.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/i3c/device.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+
+enum i3c_clks {
+	PCLK,
+	FCLK,
+	SCLK,
+	MAXCLK,
+};
+
+struct svc_i3c_slave {
+	struct device *dev;
+	void __iomem *regs;
+	int irq;
+	struct clk_bulk_data clks[MAXCLK];
+
+	struct list_head txq;
+	spinlock_t txq_lock; /* protect tx queue */
+	struct list_head rxq;
+	spinlock_t rxq_lock; /* protect rx queue */
+	struct list_head cq;
+	spinlock_t cq_lock; /* protect complete queue */
+
+	struct work_struct work;
+	struct workqueue_struct *workqueue;
+
+	struct completion dacomplete;
+	struct i3c_slave_ctrl_features features;
+
+	spinlock_t ctrl_lock; /* protext access SCTRL register */
+};
+
+#define I3C_SCONFIG	0x4
+#define   I3C_SCONFIG_SLVENA_MASK	BIT(0)
+#define	  I3C_SCONFIG_OFFLINE_MASK	BIT(9)
+#define   I3C_SCONFIG_SADDR_MASK	GENMASK(31, 25)
+
+#define I3C_SSTATUS	0x8
+#define	  I3C_SSTATUS_STNOTSTOP_MASK	BIT(0)
+#define	  I3C_SSTATUS_STOP_MASK		BIT(10)
+#define	  I3C_SSTATUS_RX_PEND_MASK	BIT(11)
+#define   I3C_SSTATUS_TXNOTFULL_MASK	BIT(12)
+#define	  I3C_SSTATUS_DACHG_MASK	BIT(13)
+#define	  I3C_SSTATUS_EVDET_MASK	GENMASK(21, 20)
+#define	  I3C_SSTATUS_EVDET_ACKED	0x3
+#define	  I3C_SSTATUS_IBIDIS_MASK	BIT(24)
+#define	  I3C_SSTATUS_HJDIS_MASK	BIT(27)
+
+#define I3C_SCTRL	0xc
+#define   I3C_SCTRL_EVENT_MASK		GENMASK(1, 0)
+#define	  I3C_SCTRL_EVENT_IBI		0x1
+#define	  I3C_SCTRL_EVENT_HOTJOIN	0x3
+#define   I3C_SCTRL_EXTDATA_MASK	BIT(3)
+#define   I3C_SCTRL_IBIDATA_MASK	GENMASK(15, 8)
+
+#define I3C_SINTSET	0x10
+#define I3C_SINTCLR	0x14
+#define   I3C_SINT_START	BIT(8)
+#define   I3C_SINT_MATCHED	BIT(9)
+#define   I3C_SINT_STOP		BIT(10)
+#define   I3C_SINT_RXPEND	BIT(11)
+#define   I3C_SINT_TXSEND	BIT(12)
+#define   I3C_SINT_DACHG	BIT(13)
+#define   I3C_SINT_CCC		BIT(14)
+#define   I3C_SINT_ERRWARN	BIT(15)
+#define   I3C_SINT_DDRMAATCHED	BIT(16)
+#define   I3C_SINT_CHANDLED	BIT(17)
+#define   I3C_SINT_EVENT	BIT(18)
+#define   I3C_SINT_SLVRST	BIT(19)
+
+#define I3C_SDATACTRL	0x2c
+#define   I3C_SDATACTRL_RXEMPTY_MASK	BIT(31)
+#define   I3C_SDATACTRL_TXFULL_MASK	BIT(30)
+#define	  I3C_SDATACTRL_RXCOUNT_MASK	GENMASK(28, 24)
+#define	  I3C_SDATACTRL_TXCOUNT_MASK	GENMASK(20, 16)
+#define   I3C_SDATACTRL_FLUSHFB_MASK	BIT(1)
+#define   I3C_SDATACTRL_FLUSHTB_MASK	BIT(0)
+
+#define I3C_SWDATAB	0x30
+#define   I3C_SWDATAB_END_ALSO_MASK	BIT(16)
+#define	  I3C_SWDATAB_END_MASK		BIT(8)
+
+#define I3C_SWDATAE	0x34
+#define I3C_SRDATAB	0x40
+
+#define I3C_SCAPABILITIES 0x60
+#define   I3C_SCAPABILITIES_FIFOTX_MASK     GENMASK(27, 26)
+#define   I3C_SCAPABILITIES_FIFORX_MASK     GENMASK(29, 28)
+
+#define I3C_SMAXLIMITS	0x68
+#define   I3C_SMAXLIMITS_MAXRD_MASK  GENMASK(11, 0)
+#define   I3C_SMAXLIMITS_MAXWR_MASK  GENMASK(27, 16)
+
+#define I3C_SIDPARTNO	0x6c
+
+#define I3C_SIDEXT	0x70
+#define	  I3C_SIDEXT_BCR_MASK	GENMASK(23, 16)
+#define	  I3C_SIDEXT_DCR_MASK	GENMASK(15, 8)
+#define I3C_SVENDORID	0x74
+
+#define I3C_SMAPCTRL0	0x11c
+#define	  I3C_SMAPCTRL0_ENA_MASK	BIT(0)
+#define   I3C_SMAPCTRL0_DA_MASK	GENMASK(7, 1)
+
+#define I3C_IBIEXT1	0x140
+#define   I3C_IBIEXT1_CNT_MASK	GEN_MASK(2, 0)
+#define   I3C_IBIEXT1_MAX_MASK	GEN_MASK(4, 6)
+#define   I3C_IBIEXT1_EXT1_SHIFT	8
+#define   I3C_IBIEXT1_EXT2_SHIFT	16
+#define   I3C_IBIEXT1_EXT3_SHIFT	24
+
+#define I3C_IBIEXT2	0x144
+#define	  I3C_IBIEXT2_EXT4_SHIFT	0
+#define	  I3C_IBIEXT2_EXT5_SHIFT	8
+#define	  I3C_IBIEXT2_EXT6_SHIFT	16
+#define	  I3C_IBIEXT2_EXT7_SHIFT	24
+
+static int svc_i3c_slave_enable(struct i3c_slave_ctrl *ctrl)
+{
+	struct svc_i3c_slave *svc;
+	u32 val;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+
+	val = readl_relaxed(svc->regs + I3C_SCONFIG);
+	val |= I3C_SCONFIG_SLVENA_MASK;
+	writel_relaxed(val, svc->regs + I3C_SCONFIG);
+
+	return 0;
+}
+
+static int svc_i3c_slave_disable(struct i3c_slave_ctrl *ctrl)
+{
+	struct svc_i3c_slave *svc;
+	u32 val;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+
+	val = readl_relaxed(svc->regs + I3C_SCONFIG);
+	val &= ~I3C_SCONFIG_SLVENA_MASK;
+	writel_relaxed(val, svc->regs + I3C_SCONFIG);
+
+	return 0;
+}
+
+static int svc_i3c_slave_set_config(struct i3c_slave_ctrl *ctrl, struct i3c_slave_func *func)
+{
+	struct svc_i3c_slave *svc;
+	u32 val;
+	u32 wm, rm;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+
+	if (func->static_addr > 0x7F)
+		return -EINVAL;
+
+	val = readl_relaxed(svc->regs + I3C_SCONFIG);
+	val &= ~I3C_SCONFIG_SLVENA_MASK;
+	val |= FIELD_PREP(I3C_SCONFIG_SADDR_MASK, func->static_addr);
+	writel_relaxed(val, svc->regs + I3C_SCONFIG);
+
+	if (func->part_id)
+		writel_relaxed((func->part_id << 16) |
+				((func->instance_id << 12) & GENMASK(15, 12)) |
+				(func->ext_id & GENMASK(11, 0)), svc->regs + I3C_SIDPARTNO);
+
+	writel_relaxed(FIELD_PREP(I3C_SIDEXT_BCR_MASK, func->bcr) |
+		       FIELD_PREP(I3C_SIDEXT_DCR_MASK, func->dcr),
+		       svc->regs + I3C_SIDEXT);
+
+	wm = func->max_write_len == 0 ?
+	     FIELD_GET(I3C_SMAXLIMITS_MAXWR_MASK, I3C_SMAXLIMITS_MAXWR_MASK) : func->max_write_len;
+
+	wm = max_t(u32, val, 8);
+
+	rm = func->max_read_len == 0 ?
+	     FIELD_GET(I3C_SMAXLIMITS_MAXRD_MASK, I3C_SMAXLIMITS_MAXRD_MASK) : func->max_read_len;
+	rm = max_t(u32, val, 16);
+
+	val = FIELD_PREP(I3C_SMAXLIMITS_MAXRD_MASK, rm) | FIELD_PREP(I3C_SMAXLIMITS_MAXWR_MASK, wm);
+	writel_relaxed(val, svc->regs + I3C_SMAXLIMITS);
+
+	writel_relaxed(func->vendor_id, svc->regs + I3C_SVENDORID);
+	return 0;
+}
+
+const struct i3c_slave_ctrl_features *svc_i3c_get_features(struct i3c_slave_ctrl *ctrl)
+{
+	struct svc_i3c_slave *svc;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+
+	if (!svc)
+		return NULL;
+
+	return &svc->features;
+}
+
+static void svc_i3c_queue_complete(struct svc_i3c_slave *svc, struct i3c_request *complete)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&svc->cq_lock, flags);
+	list_add_tail(&complete->list, &svc->cq);
+	spin_unlock_irqrestore(&svc->cq_lock, flags);
+	queue_work(svc->workqueue, &svc->work);
+}
+
+static void svc_i3c_fill_txfifo(struct svc_i3c_slave *svc)
+{
+	struct i3c_request *req, *complete = NULL;
+	unsigned long flags;
+	int val;
+
+	spin_lock_irqsave(&svc->txq_lock, flags);
+	while ((!!(req = list_first_entry_or_null(&svc->txq, struct i3c_request, list))) &&
+	       !((readl_relaxed(svc->regs + I3C_SDATACTRL) & I3C_SDATACTRL_TXFULL_MASK))) {
+		while (!(readl_relaxed(svc->regs + I3C_SDATACTRL)
+					& I3C_SDATACTRL_TXFULL_MASK)) {
+			val = *(u8 *)(req->buf + req->actual);
+
+			if (req->actual + 1 == req->length)
+				writel_relaxed(val, svc->regs + I3C_SWDATAE);
+			else
+				writel_relaxed(val, svc->regs + I3C_SWDATAB);
+
+			req->actual++;
+
+			if (req->actual == req->length) {
+				list_del(&req->list);
+				complete = req;
+				spin_unlock_irqrestore(&svc->txq_lock, flags);
+
+				svc_i3c_queue_complete(svc, complete);
+
+				spin_lock_irqsave(&svc->txq_lock, flags);
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&svc->txq_lock, flags);
+}
+
+static int svc_i3c_slave_queue(struct i3c_request *req, gfp_t)
+{
+	struct svc_i3c_slave *svc;
+	struct list_head *q;
+	unsigned long flags;
+	spinlock_t *lk;
+
+	svc = dev_get_drvdata(&req->ctrl->dev);
+	if (!svc)
+		return -EINVAL;
+
+	if (req->tx) {
+		q = &svc->txq;
+		lk = &svc->txq_lock;
+	} else {
+		q = &svc->rxq;
+		lk = &svc->rxq_lock;
+	}
+
+	spin_lock_irqsave(lk, flags);
+	list_add_tail(&req->list, q);
+	spin_unlock_irqrestore(lk, flags);
+
+	if (req->tx)
+		svc_i3c_fill_txfifo(svc);
+
+	if (req->tx)
+		writel_relaxed(I3C_SINT_TXSEND, svc->regs + I3C_SINTSET);
+	else
+		writel_relaxed(I3C_SINT_RXPEND, svc->regs + I3C_SINTSET);
+
+	return 0;
+}
+
+static int svc_i3c_dequeue(struct i3c_request *req)
+{
+	struct svc_i3c_slave *svc;
+	unsigned long flags;
+	spinlock_t *lk;
+
+	svc = dev_get_drvdata(&req->ctrl->dev);
+	if (!svc)
+		return -EINVAL;
+
+	if (req->tx)
+		lk = &svc->txq_lock;
+	else
+		lk = &svc->rxq_lock;
+
+	spin_lock_irqsave(lk, flags);
+	list_del(&req->list);
+	spin_unlock_irqrestore(lk, flags);
+
+	return 0;
+}
+
+static void svc_i3c_slave_fifo_flush(struct i3c_slave_ctrl *ctrl, bool tx)
+{
+	struct svc_i3c_slave *svc;
+	u32 val;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+
+	val = readl_relaxed(svc->regs + I3C_SDATACTRL);
+
+	val |= tx ? I3C_SDATACTRL_FLUSHTB_MASK : I3C_SDATACTRL_FLUSHFB_MASK;
+
+	writel_relaxed(val, svc->regs + I3C_SDATACTRL);
+}
+
+static int
+svc_i3c_slave_raise_ibi(struct i3c_slave_ctrl *ctrl, void *p, u8 size)
+{
+	struct svc_i3c_slave *svc;
+	unsigned long flags;
+	u8 *ibidata = p;
+	u32 ext1 = 0, ext2 = 0;
+	u32 val;
+	int ret;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+
+	if (size && !p)
+		return -EINVAL;
+
+	if (size > 8)
+		return -EINVAL;
+
+	val = readl_relaxed(svc->regs + I3C_SSTATUS);
+	if (val & I3C_SSTATUS_IBIDIS_MASK)
+		return -EINVAL;
+
+	ret = readl_relaxed_poll_timeout(svc->regs + I3C_SCTRL, val,
+					 !(val & I3C_SCTRL_EVENT_MASK), 0, 10000);
+	if (ret) {
+		dev_err(&ctrl->dev, "Timeout when polling for NO event pending");
+		val &= ~I3C_SCTRL_EVENT_MASK;
+		writel_relaxed(val, svc->regs + I3C_SCTRL);
+		return -ENAVAIL;
+	}
+
+	spin_lock_irqsave(&svc->ctrl_lock, flags);
+
+	val = readl_relaxed(svc->regs + I3C_SCTRL);
+
+	val &= ~I3C_SCTRL_EVENT_MASK | I3C_SCTRL_IBIDATA_MASK;
+	val |= FIELD_PREP(I3C_SCTRL_EVENT_MASK, I3C_SCTRL_EVENT_IBI);
+
+	if (size) {
+		val |= FIELD_PREP(I3C_SCTRL_IBIDATA_MASK, *ibidata);
+		ibidata++;
+
+		if (size > 1)
+			val |= I3C_SCTRL_EXTDATA_MASK;
+
+		size--;
+		if (size > 0) {
+			ext1 |= (size + 2);
+			ext1 |= (*ibidata++) << I3C_IBIEXT1_EXT1_SHIFT;
+			size--;
+		}
+
+		if (size > 0) {
+			ext1 |= (*ibidata++) << I3C_IBIEXT1_EXT2_SHIFT;
+			size--;
+		}
+
+		if (size > 0) {
+			ext1 |= (*ibidata++) << I3C_IBIEXT1_EXT3_SHIFT;
+			size--;
+		}
+
+		writel_relaxed(ext1, svc->regs + I3C_IBIEXT1);
+
+		if (size > 0) {
+			ext2 |= (*ibidata++) << I3C_IBIEXT2_EXT4_SHIFT;
+			size--;
+		}
+
+		if (size > 0) {
+			ext2 |= (*ibidata++) << I3C_IBIEXT2_EXT5_SHIFT;
+			size--;
+		}
+
+		if (size > 0) {
+			ext2 |= (*ibidata++) << I3C_IBIEXT2_EXT6_SHIFT;
+			size--;
+		}
+
+		if (size > 0) {
+			ext2 |= (*ibidata++) << I3C_IBIEXT2_EXT7_SHIFT;
+			size--;
+		}
+
+		writeb_relaxed(ext2, svc->regs + I3C_IBIEXT2);
+	}
+
+	/* Issue IBI*/
+	writel_relaxed(val, svc->regs + I3C_SCTRL);
+	spin_unlock_irqrestore(&svc->ctrl_lock, flags);
+
+	ret = readl_relaxed_poll_timeout(svc->regs + I3C_SCTRL, val,
+					 !(val & I3C_SCTRL_EVENT_MASK), 0, 1000000);
+	if (ret) {
+		dev_err(&ctrl->dev, "Timeout when polling for IBI finish\n");
+
+		//clear event to above hang bus
+		spin_lock_irqsave(&svc->ctrl_lock, flags);
+		val = readl_relaxed(svc->regs + I3C_SCTRL);
+		val &= ~I3C_SCTRL_EVENT_MASK;
+		writel_relaxed(val, svc->regs + I3C_SCTRL);
+		spin_unlock_irqrestore(&svc->ctrl_lock, flags);
+
+		return -ENAVAIL;
+	}
+
+	return 0;
+}
+
+static void svc_i3c_slave_complete(struct work_struct *work)
+{
+	struct svc_i3c_slave *svc = container_of(work, struct svc_i3c_slave, work);
+	struct i3c_request *req;
+	unsigned long flags;
+
+	spin_lock_irqsave(&svc->cq_lock, flags);
+	while (!list_empty(&svc->cq)) {
+		req = list_first_entry(&svc->cq, struct i3c_request, list);
+		list_del(&req->list);
+		spin_unlock_irqrestore(&svc->cq_lock, flags);
+		req->complete(req);
+
+		spin_lock_irqsave(&svc->cq_lock, flags);
+	}
+	spin_unlock_irqrestore(&svc->cq_lock, flags);
+}
+
+static irqreturn_t svc_i3c_slave_irq_handler(int irq, void *dev_id)
+{
+	struct i3c_request *req, *complete = NULL;
+	struct svc_i3c_slave *svc = dev_id;
+	unsigned long flags;
+	u32 statusFlags;
+
+	statusFlags = readl(svc->regs + I3C_SSTATUS);
+	writel(statusFlags, svc->regs + I3C_SSTATUS);
+
+	if (statusFlags & I3C_SSTATUS_DACHG_MASK)
+		complete_all(&svc->dacomplete);
+
+	if (statusFlags & I3C_SSTATUS_RX_PEND_MASK) {
+		spin_lock_irqsave(&svc->rxq_lock, flags);
+		req = list_first_entry_or_null(&svc->rxq, struct i3c_request, list);
+
+		if (!req) {
+			writel_relaxed(I3C_SINT_RXPEND, svc->regs + I3C_SINTCLR);
+		} else {
+			while (!(readl_relaxed(svc->regs + I3C_SDATACTRL) &
+					       I3C_SDATACTRL_RXEMPTY_MASK)) {
+				*(u8 *)(req->buf + req->actual) =
+							readl_relaxed(svc->regs + I3C_SRDATAB);
+				req->actual++;
+
+				if (req->actual == req->length) {
+					complete = req;
+					list_del(&req->list);
+					break;
+				}
+			}
+
+			if (req->actual != req->length && (statusFlags & I3C_SSTATUS_STOP_MASK)) {
+				complete = req;
+				list_del(&req->list);
+			}
+		}
+		spin_unlock_irqrestore(&svc->rxq_lock, flags);
+
+		if (complete) {
+			spin_lock_irqsave(&svc->cq_lock, flags);
+			list_add_tail(&complete->list, &svc->cq);
+			spin_unlock_irqrestore(&svc->cq_lock, flags);
+			queue_work(svc->workqueue, &svc->work);
+			complete = NULL;
+		}
+	}
+
+	if (statusFlags & I3C_SSTATUS_TXNOTFULL_MASK) {
+		svc_i3c_fill_txfifo(svc);
+
+		spin_lock_irqsave(&svc->txq_lock, flags);
+		if (list_empty(&svc->txq))
+			writel_relaxed(I3C_SINT_TXSEND, svc->regs + I3C_SINTCLR);
+		spin_unlock_irqrestore(&svc->txq_lock, flags);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void svc_i3c_cancel_all_reqs(struct i3c_slave_ctrl *ctrl, bool tx)
+{
+	struct svc_i3c_slave *svc;
+	struct i3c_request *req;
+	struct list_head *q;
+	unsigned long flags;
+	spinlock_t *lk;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+	if (!svc)
+		return;
+
+	if (tx) {
+		q = &svc->txq;
+		lk = &svc->txq_lock;
+	} else {
+		q = &svc->rxq;
+		lk = &svc->rxq_lock;
+	}
+
+	spin_lock_irqsave(lk, flags);
+	while (!list_empty(q)) {
+		req = list_first_entry(q, struct i3c_request, list);
+		list_del(&req->list);
+		spin_unlock_irqrestore(lk, flags);
+
+		req->status = I3C_REQUEST_CANCEL;
+		req->complete(req);
+		spin_lock_irqsave(lk, flags);
+	}
+	spin_unlock_irqrestore(lk, flags);
+}
+
+static int svc_i3c_hotjoin(struct i3c_slave_ctrl *ctrl)
+{
+	struct svc_i3c_slave *svc;
+	int ret;
+	u32 val;
+	u32 cfg;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+	if (!svc)
+		return -EINVAL;
+
+	reinit_completion(&svc->dacomplete);
+
+	val = readl_relaxed(svc->regs + I3C_SSTATUS);
+	if (val & I3C_SSTATUS_HJDIS_MASK) {
+		dev_err(&ctrl->dev, "Hotjoin disabled by i3c master\n");
+		return -EINVAL;
+	}
+
+	ret = readl_relaxed_poll_timeout(svc->regs + I3C_SCTRL, val,
+					 !(val & I3C_SCTRL_EVENT_MASK), 0, 10000);
+	if (ret) {
+		dev_err(&ctrl->dev, "Timeout when polling for none event pending");
+		return -ENAVAIL;
+	}
+
+	cfg = readl_relaxed(svc->regs + I3C_SCONFIG);
+	cfg |= I3C_SCONFIG_OFFLINE_MASK;
+	writel_relaxed(cfg, svc->regs + I3C_SCONFIG);
+
+	val &= ~(I3C_SCTRL_EVENT_MASK | I3C_SCTRL_IBIDATA_MASK);
+	val |= FIELD_PREP(I3C_SCTRL_EVENT_MASK, I3C_SCTRL_EVENT_HOTJOIN);
+	/* Issue hotjoin*/
+	writel_relaxed(val, svc->regs + I3C_SCTRL);
+
+	ret = readl_relaxed_poll_timeout(svc->regs + I3C_SCTRL, val,
+					 !(val & I3C_SCTRL_EVENT_MASK), 0, 100000);
+	if (ret) {
+		val &= ~FIELD_PREP(I3C_SCTRL_EVENT_MASK, I3C_SCTRL_EVENT_MASK);
+		writel_relaxed(val, svc->regs + I3C_SCTRL);
+		dev_err(&ctrl->dev, "Timeout when polling for HOTJOIN finish\n");
+		return -EINVAL;
+	}
+
+	val = readl_relaxed(svc->regs + I3C_SSTATUS);
+	val = FIELD_GET(I3C_SSTATUS_EVDET_MASK, val);
+	if (val != I3C_SSTATUS_EVDET_ACKED) {
+		dev_err(&ctrl->dev, "Master NACKED hotjoin request\n");
+		return -EINVAL;
+	}
+
+	writel_relaxed(I3C_SINT_DACHG, svc->regs + I3C_SINTSET);
+	ret = wait_for_completion_timeout(&svc->dacomplete, msecs_to_jiffies(100));
+	writel_relaxed(I3C_SINT_DACHG, svc->regs + I3C_SINTCLR);
+	if (!ret) {
+		dev_err(&ctrl->dev, "wait for da assignment timeout\n");
+		return -EIO;
+	}
+
+	val = readl_relaxed(svc->regs + I3C_SMAPCTRL0);
+	val = FIELD_GET(I3C_SMAPCTRL0_DA_MASK, val);
+	dev_info(&ctrl->dev, "Get dynamtic address 0x%x\n", val);
+	return 0;
+}
+
+static int svc_i3c_set_status_format1(struct i3c_slave_ctrl *ctrl, u16 status)
+{
+	struct svc_i3c_slave *svc;
+	unsigned long flags;
+	u32 val;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+
+	spin_lock_irqsave(&svc->ctrl_lock, flags);
+	val = readl_relaxed(svc->regs + I3C_SCTRL);
+	val &= 0xFFFF;
+	val |= status << 16;
+	writel_relaxed(val, svc->regs + I3C_SCTRL);
+	spin_unlock_irqrestore(&svc->ctrl_lock, flags);
+
+	return 0;
+}
+
+static u16 svc_i3c_get_status_format1(struct i3c_slave_ctrl *ctrl)
+{
+	struct svc_i3c_slave *svc;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+
+	return readl_relaxed(svc->regs + I3C_SCTRL) >> 16;
+}
+
+static u8 svc_i3c_get_addr(struct i3c_slave_ctrl *ctrl)
+{
+	struct svc_i3c_slave *svc;
+	int val;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+
+	val = readl_relaxed(svc->regs + I3C_SMAPCTRL0);
+
+	if (val & I3C_SMAPCTRL0_ENA_MASK)
+		return FIELD_GET(I3C_SMAPCTRL0_DA_MASK, val);
+
+	return 0;
+}
+
+int svc_i3c_fifo_status(struct i3c_slave_ctrl *ctrl, bool tx)
+{
+	struct svc_i3c_slave *svc;
+	int val;
+
+	svc = dev_get_drvdata(&ctrl->dev);
+
+	val = readl_relaxed(svc->regs + I3C_SDATACTRL);
+
+	if (tx)
+		return FIELD_GET(I3C_SDATACTRL_TXCOUNT_MASK, val);
+	else
+		return FIELD_GET(I3C_SDATACTRL_RXCOUNT_MASK, val);
+}
+
+static struct i3c_slave_ctrl_ops svc_i3c_slave_ops = {
+	.set_config = svc_i3c_slave_set_config,
+	.enable = svc_i3c_slave_enable,
+	.disable = svc_i3c_slave_disable,
+	.queue = svc_i3c_slave_queue,
+	.dequeue = svc_i3c_dequeue,
+	.raise_ibi = svc_i3c_slave_raise_ibi,
+	.fifo_flush = svc_i3c_slave_fifo_flush,
+	.cancel_all_reqs = svc_i3c_cancel_all_reqs,
+	.get_features = svc_i3c_get_features,
+	.hotjoin = svc_i3c_hotjoin,
+	.fifo_status = svc_i3c_fifo_status,
+	.set_status_format1 = svc_i3c_set_status_format1,
+	.get_status_format1 = svc_i3c_get_status_format1,
+	.get_addr = svc_i3c_get_addr,
+};
+
+static int svc_i3c_slave_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct i3c_slave_ctrl *slave;
+	struct svc_i3c_slave *svc;
+	int ret;
+	u32 val;
+
+	svc = devm_kzalloc(dev, sizeof(*svc), GFP_KERNEL);
+	if (!svc)
+		return -ENOMEM;
+
+	svc->regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(svc->regs))
+		return PTR_ERR(svc->regs);
+
+	svc->clks[PCLK].id = "pclk";
+	svc->clks[FCLK].id = "fast_clk";
+	svc->clks[SCLK].id = "slow_clk";
+
+	ret = devm_clk_bulk_get(dev, MAXCLK, svc->clks);
+	if (ret < 0) {
+		dev_err(dev, "fail get clks: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_bulk_prepare_enable(MAXCLK, svc->clks);
+	if (ret < 0) {
+		dev_err(dev, "fail enable clks: %d\n", ret);
+		return ret;
+	}
+
+	svc->irq = platform_get_irq(pdev, 0);
+	if (svc->irq < 0)
+		return svc->irq;
+
+	INIT_LIST_HEAD(&svc->txq);
+	INIT_LIST_HEAD(&svc->rxq);
+	INIT_LIST_HEAD(&svc->cq);
+	spin_lock_init(&svc->txq_lock);
+	spin_lock_init(&svc->rxq_lock);
+	spin_lock_init(&svc->cq_lock);
+	spin_lock_init(&svc->ctrl_lock);
+
+	init_completion(&svc->dacomplete);
+
+	INIT_WORK(&svc->work, svc_i3c_slave_complete);
+	svc->workqueue = alloc_workqueue("%s-cq", 0, 0, dev_name(dev));
+	if (!svc->workqueue)
+		return -ENOMEM;
+
+	/* Disable all IRQ */
+	writel_relaxed(0xFFFFFFFF, svc->regs + I3C_SINTCLR);
+
+	val = readl_relaxed(svc->regs + I3C_SCAPABILITIES);
+	svc->features.tx_fifo_sz  = FIELD_GET(I3C_SCAPABILITIES_FIFOTX_MASK, val);
+	svc->features.tx_fifo_sz = 2 << svc->features.tx_fifo_sz;
+
+	svc->features.rx_fifo_sz = FIELD_GET(I3C_SCAPABILITIES_FIFORX_MASK, val);
+	svc->features.rx_fifo_sz = 2 << svc->features.rx_fifo_sz;
+
+	ret = devm_request_irq(dev, svc->irq, svc_i3c_slave_irq_handler, 0, "svc-i3c-irq", svc);
+	if (ret)
+		return -ENOENT;
+
+	slave = devm_i3c_slave_ctrl_create(dev, &svc_i3c_slave_ops);
+	if (!slave)
+		return -ENOMEM;
+
+	dev_set_drvdata(&slave->dev, svc);
+
+	return 0;
+}
+
+static int svc_i3c_slave_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct of_device_id svc_i3c_slave_of_match_tbl[] = {
+	{ .compatible = "silvaco,i3c-slave-v1" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, svc_i3c_slave_of_match_tbl);
+
+static struct platform_driver svc_i3c_slave = {
+	.probe = svc_i3c_slave_probe,
+	.remove = svc_i3c_slave_remove,
+	.driver = {
+		.name = "silvaco-i3c-slave",
+		.of_match_table = svc_i3c_slave_of_match_tbl,
+		//.pm = &svc_i3c_pm_ops,
+	},
+};
+module_platform_driver(svc_i3c_slave);
+
+MODULE_DESCRIPTION("Silvaco dual-role I3C slave driver");
+MODULE_LICENSE("GPL");
-- 
2.34.1


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

* [PATCH 4/5] i3c: slave: func: add tty driver
  2023-10-18 21:58 [PATCH 0/5] I3C slave mode support Frank Li
                   ` (2 preceding siblings ...)
  2023-10-18 21:58 ` [PATCH 3/5] i3c: slave: add svc slave controller support Frank Li
@ 2023-10-18 21:58 ` Frank Li
  2023-10-19  7:21   ` Jiri Slaby
  2023-10-18 21:58 ` [PATCH 5/5] Documentation: i3c: Add I3C slave mode controller and function Frank Li
  4 siblings, 1 reply; 17+ messages in thread
From: Frank Li @ 2023-10-18 21:58 UTC (permalink / raw)
  To: miquel.raynal, conor.culhane, alexandre.belloni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, joe, Frank.Li,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: gregkh, imx, jirislaby, linux-serial

Add tty over I3C slave function driver.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 drivers/i3c/Kconfig       |   1 +
 drivers/i3c/Makefile      |   1 +
 drivers/i3c/func/Kconfig  |   9 +
 drivers/i3c/func/Makefile |   3 +
 drivers/i3c/func/tty.c    | 548 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 562 insertions(+)
 create mode 100644 drivers/i3c/func/Kconfig
 create mode 100644 drivers/i3c/func/Makefile
 create mode 100644 drivers/i3c/func/tty.c

diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig
index 802a9b3576f13..9b87cb4a84d85 100644
--- a/drivers/i3c/Kconfig
+++ b/drivers/i3c/Kconfig
@@ -50,4 +50,5 @@ config I3C_SLAVE_CONFIGFS
 
 if I3C_SLAVE
 source "drivers/i3c/slave/Kconfig"
+source "drivers/i3c/func/Kconfig"
 endif # I3C_SLAVE
diff --git a/drivers/i3c/Makefile b/drivers/i3c/Makefile
index ef1acbe13fe60..7814bf2dd9b40 100644
--- a/drivers/i3c/Makefile
+++ b/drivers/i3c/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_I3C)		+= master/
 obj-$(CONFIG_I3C_SLAVE)		+= slave.o
 obj-$(CONFIG_I3C_SLAVE_CONFIGFS)	+= i3c-cfs.o
 obj-$(CONFIG_I3C_SLAVE)		+= slave/
+obj-$(CONFIG_I3C_SLAVE)		+= func/
diff --git a/drivers/i3c/func/Kconfig b/drivers/i3c/func/Kconfig
new file mode 100644
index 0000000000000..3ebf5bd2592a2
--- /dev/null
+++ b/drivers/i3c/func/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config I3C_SLAVE_FUNC_TTY
+	tristate "PCI Endpoint Test driver"
+	depends on I3C_SLAVE
+	help
+	  I3C Slave TTY Function Driver.
+
+	  General TTY over I3C slave controller function drivers.
diff --git a/drivers/i3c/func/Makefile b/drivers/i3c/func/Makefile
new file mode 100644
index 0000000000000..db3262e402edd
--- /dev/null
+++ b/drivers/i3c/func/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_I3C_SLAVE_FUNC_TTY)              += tty.o
diff --git a/drivers/i3c/func/tty.c b/drivers/i3c/func/tty.c
new file mode 100644
index 0000000000000..ea48db49b2764
--- /dev/null
+++ b/drivers/i3c/func/tty.c
@@ -0,0 +1,548 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 NXP
+ * Author: Frank Li <Frank.Li@nxp.com>
+ */
+
+#include <linux/iopoll.h>
+#include <linux/i3c/slave.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty_flip.h>
+
+static DEFINE_IDR(i3c_tty_minors);
+static DEFINE_MUTEX(i3c_tty_minors_lock);
+
+static struct tty_driver *i3c_tty_driver;
+
+#define I3C_TTY_MINORS		256
+
+#define I3C_TX_NOEMPTY		BIT(0)
+#define I3C_TTY_TRANS_SIZE	16
+#define I3C_TTY_IBI_TX		BIT(0)
+
+struct ttyi3c_port {
+	struct tty_port port;
+	int minor;
+	struct i3c_slave_func *i3cdev;
+	struct circ_buf xmit;
+	int tail_in_queue;
+	struct completion txcomplete;
+	spinlock_t xlock;
+	void *buffer;
+	struct work_struct work;
+	struct workqueue_struct	*workqueue;
+	u16 status;
+};
+
+static void i3c_slave_tty_rx_complete(struct i3c_request *req)
+{
+	struct ttyi3c_port *port = req->context;
+
+	if (req->status == I3C_REQUEST_CANCEL) {
+		i3c_slave_ctrl_free_request(req);
+		return;
+	}
+
+	for (int i = 0; i < req->actual; i++)
+		tty_insert_flip_char(&port->port, *(u8 *)(req->buf + i), 0);
+
+	tty_flip_buffer_push(&port->port);
+	req->actual = 0;
+	req->status = 0;
+	i3c_slave_ctrl_queue(req, GFP_KERNEL);
+}
+
+static void i3c_slave_tty_tx_complete(struct i3c_request *req)
+{
+	struct ttyi3c_port *sport = req->context;
+	struct circ_buf *xmit = &sport->xmit;
+	unsigned long flags;
+	int cnt;
+
+	if (req->status == I3C_REQUEST_CANCEL) {
+		i3c_slave_ctrl_free_request(req);
+		return;
+	}
+
+	spin_lock_irqsave(&sport->xlock, flags);
+	xmit->tail = (xmit->tail + req->actual) & (UART_XMIT_SIZE - 1);
+	cnt = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
+	if (cnt == 0)
+		complete(&sport->txcomplete);
+	else
+		queue_work(sport->workqueue, &sport->work);
+
+	spin_unlock_irqrestore(&sport->xlock, flags);
+
+	if (cnt < WAKEUP_CHARS)
+		tty_port_tty_wakeup(&sport->port);
+
+	i3c_slave_ctrl_free_request(req);
+}
+
+static void i3c_slave_tty_i3c_work(struct work_struct *work)
+{
+	struct ttyi3c_port *sport = container_of(work, struct ttyi3c_port, work);
+	struct circ_buf *xmit = &sport->xmit;
+	int cnt = CIRC_CNT(xmit->head, sport->tail_in_queue, UART_XMIT_SIZE);
+	u8 ibi;
+
+	if (cnt == 0)
+		return;
+
+	while (cnt > 0) {
+		struct i3c_request *req = i3c_slave_ctrl_alloc_request(sport->i3cdev->ctrl,
+								       GFP_KERNEL);
+		if (!req)
+			return;
+
+		req->length = CIRC_CNT_TO_END(xmit->head, sport->tail_in_queue, UART_XMIT_SIZE);
+
+		req->buf =  xmit->buf + sport->tail_in_queue;
+		req->complete = i3c_slave_tty_tx_complete;
+		req->context = sport;
+		req->tx = true;
+
+		if (i3c_slave_ctrl_queue(req, GFP_KERNEL))
+			return;
+
+		sport->tail_in_queue += req->length;
+		sport->tail_in_queue &= UART_XMIT_SIZE - 1;
+
+		cnt = CIRC_CNT(xmit->head, sport->tail_in_queue, UART_XMIT_SIZE);
+	}
+
+	ibi = I3C_TTY_IBI_TX;
+	i3c_slave_ctrl_raise_ibi(sport->i3cdev->ctrl, &ibi, 1);
+}
+
+static int i3c_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+	struct ttyi3c_port *sport = container_of(port, struct ttyi3c_port, port);
+	const struct i3c_slave_ctrl_features *feature;
+	struct i3c_slave_func *func = sport->i3cdev;
+	struct i3c_request *req;
+	int rxfifo_size;
+	int offset = 0;
+
+	feature = i3c_slave_ctrl_get_features(func->ctrl);
+	if (!feature)
+		return -EINVAL;
+
+	rxfifo_size = feature->rx_fifo_sz;
+
+	if (!rxfifo_size)
+		rxfifo_size = I3C_TTY_TRANS_SIZE;
+
+	do {
+		req = i3c_slave_ctrl_alloc_request(func->ctrl, GFP_KERNEL);
+		if (!req)
+			goto err;
+
+		req->buf = (void *) (sport->buffer + offset);
+		req->length = rxfifo_size;
+		req->context = sport;
+		req->complete = i3c_slave_tty_rx_complete;
+		offset += rxfifo_size;
+
+		if (i3c_slave_ctrl_queue(req, GFP_KERNEL))
+			goto err;
+	} while (req && (offset + rxfifo_size) < UART_XMIT_SIZE);
+
+	reinit_completion(&sport->txcomplete);
+
+	return 0;
+err:
+	i3c_slave_ctrl_cancel_all_reqs(func->ctrl, false);
+	return -ENOMEM;
+}
+
+static void i3c_port_shutdown(struct tty_port *port)
+{
+	struct ttyi3c_port *sport =
+		container_of(port, struct ttyi3c_port, port);
+
+	cancel_work_sync(&sport->work);
+
+	i3c_slave_ctrl_cancel_all_reqs(sport->i3cdev->ctrl, true);
+	i3c_slave_ctrl_cancel_all_reqs(sport->i3cdev->ctrl, false);
+
+	sport->xmit.tail = sport->tail_in_queue = sport->xmit.head;
+
+	i3c_slave_ctrl_fifo_flush(sport->i3cdev->ctrl, true);
+	i3c_slave_ctrl_fifo_flush(sport->i3cdev->ctrl, false);
+}
+
+static void i3c_port_destruct(struct tty_port *port)
+{
+	struct ttyi3c_port *sport =
+		container_of(port, struct ttyi3c_port, port);
+
+	mutex_lock(&i3c_tty_minors_lock);
+	idr_remove(&i3c_tty_minors, sport->minor);
+	mutex_unlock(&i3c_tty_minors_lock);
+}
+
+static const struct tty_port_operations i3c_port_ops = {
+	.shutdown = i3c_port_shutdown,
+	.activate = i3c_port_activate,
+	.destruct = i3c_port_destruct,
+};
+
+static int i3c_slave_tty_bind(struct i3c_slave_func *func)
+{
+	struct ttyi3c_port *sport;
+	struct device *tty_dev;
+	int minor;
+	int ret;
+
+	sport = dev_get_drvdata(&func->dev);
+
+	if (i3c_slave_ctrl_set_config(func->ctrl, func)) {
+		dev_err(&func->dev, "failure set i3c config\n");
+		return -EINVAL;
+	}
+
+	sport->buffer = (void *)get_zeroed_page(GFP_KERNEL);
+	if (!sport->buffer)
+		return -ENOMEM;
+
+	sport->xmit.buf = (void *)get_zeroed_page(GFP_KERNEL);
+	if (!sport->xmit.buf)
+		goto err_alloc_xmit;
+
+
+	spin_lock_init(&sport->xlock);
+	init_completion(&sport->txcomplete);
+
+	mutex_lock(&i3c_tty_minors_lock);
+	ret = minor = idr_alloc(&i3c_tty_minors, sport, 0, I3C_TTY_MINORS, GFP_KERNEL);
+	mutex_unlock(&i3c_tty_minors_lock);
+
+	if (minor < 0)
+		goto err_idr_alloc;
+
+	tty_port_init(&sport->port);
+	sport->port.ops = &i3c_port_ops;
+
+	tty_dev = tty_port_register_device(&sport->port, i3c_tty_driver, minor,
+					   &func->dev);
+	if (IS_ERR(tty_dev)) {
+		ret = PTR_ERR(tty_dev);
+		goto err_register_port;
+	}
+
+	sport->minor = minor;
+	ret = i3c_slave_ctrl_enable(func->ctrl);
+	if (ret)
+		goto err_ctrl_enable;
+
+	return 0;
+
+err_ctrl_enable:
+	tty_port_unregister_device(&sport->port, i3c_tty_driver, sport->minor);
+err_register_port:
+	mutex_lock(&i3c_tty_minors_lock);
+	idr_remove(&i3c_tty_minors, sport->minor);
+	mutex_unlock(&i3c_tty_minors_lock);
+err_idr_alloc:
+	i3c_slave_ctrl_cancel_all_reqs(func->ctrl, false);
+	free_page((unsigned long)sport->xmit.buf);
+err_alloc_xmit:
+	free_page((unsigned long)sport->buffer);
+
+	dev_err(&func->dev, "bind failure\n");
+
+	return ret;
+}
+
+static void i3c_slave_tty_unbind(struct i3c_slave_func *func)
+{
+	struct ttyi3c_port *sport;
+
+	sport = dev_get_drvdata(&func->dev);
+
+	cancel_work_sync(&sport->work);
+
+	i3c_slave_ctrl_disable(func->ctrl);
+	i3c_slave_ctrl_cancel_all_reqs(func->ctrl, 0);
+	i3c_slave_ctrl_cancel_all_reqs(func->ctrl, 1);
+
+	tty_port_unregister_device(&sport->port, i3c_tty_driver, sport->minor);
+
+	free_page((unsigned long)sport->buffer);
+}
+
+static struct i3c_slave_func_ops i3c_func_ops = {
+	.bind   = i3c_slave_tty_bind,
+	.unbind = i3c_slave_tty_unbind,
+};
+
+static int i3c_tty_probe(struct i3c_slave_func *func)
+{
+	struct device *dev = &func->dev;
+	struct ttyi3c_port *port;
+
+	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->i3cdev = func;
+	dev_set_drvdata(&func->dev, port);
+
+	port->workqueue = alloc_workqueue("%s", 0, 0, dev_name(&func->dev));
+	if (!port->workqueue)
+		return -ENOMEM;
+
+	INIT_WORK(&port->work, i3c_slave_tty_i3c_work);
+
+	return 0;
+}
+
+static void  i3c_tty_remove(struct i3c_slave_func *func)
+{
+	struct ttyi3c_port *port;
+
+	port = dev_get_drvdata(&func->dev);
+
+	destroy_workqueue(port->workqueue);
+}
+
+static struct ttyi3c_port *i3c_get_by_minor(unsigned int minor)
+{
+	struct ttyi3c_port *sport;
+
+	mutex_lock(&i3c_tty_minors_lock);
+	sport = idr_find(&i3c_tty_minors, minor);
+	mutex_unlock(&i3c_tty_minors_lock);
+
+	return sport;
+}
+
+static int i3c_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+	struct ttyi3c_port *sport;
+	int ret;
+
+	sport = i3c_get_by_minor(tty->index);
+	if (!sport)
+		return -ENODEV;
+
+	ret = tty_standard_install(driver, tty);
+	if (ret)
+		return ret;
+
+	tty->driver_data = sport;
+
+	return 0;
+}
+
+static ssize_t i3c_write(struct tty_struct *tty, const unsigned char *buf, size_t count)
+{
+	struct ttyi3c_port *sport = tty->driver_data;
+	struct circ_buf *circ = &sport->xmit;
+	unsigned long flags;
+	int c, ret = 0;
+
+	spin_lock_irqsave(&sport->xlock, flags);
+	while (1) {
+		c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
+		if (count < c)
+			c = count;
+		if (c <= 0)
+			break;
+
+		memcpy(circ->buf + circ->head, buf, c);
+		circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
+		buf += c;
+		count -= c;
+		ret += c;
+	}
+	i3c_slave_ctrl_set_status_format1(sport->i3cdev->ctrl, sport->status | I3C_TX_NOEMPTY);
+	spin_unlock_irqrestore(&sport->xlock, flags);
+
+	if (circ->head != circ->tail)
+		queue_work(sport->workqueue, &sport->work);
+
+	return ret;
+}
+
+static int i3c_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct ttyi3c_port *sport = tty->driver_data;
+	struct circ_buf *circ = &sport->xmit;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&sport->xlock, flags);
+
+	if (sport && CIRC_SPACE(circ->head, circ->tail, UART_XMIT_SIZE) != 0) {
+		circ->buf[circ->head] = ch;
+		circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
+		ret = 1;
+	}
+
+	spin_unlock_irqrestore(&sport->xlock, flags);
+
+	return ret;
+}
+
+static void i3c_flush_chars(struct tty_struct *tty)
+{
+	struct ttyi3c_port *sport = tty->driver_data;
+	struct circ_buf *circ = &sport->xmit;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sport->xlock, flags);
+	if (CIRC_SPACE(circ->head, circ->tail, UART_XMIT_SIZE))
+		queue_work(sport->workqueue, &sport->work);
+	spin_unlock_irqrestore(&sport->xlock, flags);
+}
+
+static unsigned int i3c_write_room(struct tty_struct *tty)
+{
+	struct ttyi3c_port *sport = tty->driver_data;
+	struct circ_buf *circ = &sport->xmit;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&sport->xlock, flags);
+	ret = CIRC_SPACE(circ->head, circ->tail, UART_XMIT_SIZE);
+	spin_unlock_irqrestore(&sport->xlock, flags);
+
+	return ret;
+}
+
+static void i3c_throttle(struct tty_struct *tty)
+{
+	struct ttyi3c_port *sport = tty->driver_data;
+
+	i3c_slave_ctrl_cancel_all_reqs(sport->i3cdev->ctrl, false);
+}
+
+static void i3c_unthrottle(struct tty_struct *tty)
+{
+	struct ttyi3c_port *sport = tty->driver_data;
+
+	i3c_port_activate(&sport->port, tty);
+}
+
+static int i3c_open(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyi3c_port *sport = tty->driver_data;
+	int ret;
+
+	if (!i3c_slave_ctrl_get_addr(sport->i3cdev->ctrl)) {
+		dev_info(&sport->i3cdev->dev, "No slave addr assigned, try hotjoin");
+		ret = i3c_slave_ctrl_hotjoin(sport->i3cdev->ctrl);
+		if (ret) {
+			dev_err(&sport->i3cdev->dev, "Hotjoin failure, check connection");
+			return ret;
+		}
+	}
+
+	return tty_port_open(&sport->port, tty, filp);
+}
+
+static void i3c_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyi3c_port *sport = tty->driver_data;
+
+	if (!sport)
+		return;
+
+	tty_port_close(tty->port, tty, filp);
+}
+
+static void i3c_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct ttyi3c_port *sport = tty->driver_data;
+	struct circ_buf *circ = &sport->xmit;
+	int val;
+	int ret;
+	u8 ibi = I3C_TTY_IBI_TX;
+	int retry = 100;
+
+	if (circ->head != circ->tail) {
+
+		do {
+			ret = wait_for_completion_timeout(&sport->txcomplete, timeout / 100);
+			if (ret)
+				break;
+			i3c_slave_ctrl_raise_ibi(sport->i3cdev->ctrl, &ibi, 1);
+		} while (retry--);
+
+		reinit_completion(&sport->txcomplete);
+	}
+
+	read_poll_timeout(i3c_slave_ctrl_fifo_status, val, !val, 100, timeout, false,
+			  sport->i3cdev->ctrl, true);
+
+	i3c_slave_ctrl_set_status_format1(sport->i3cdev->ctrl, sport->status & (~I3C_TX_NOEMPTY));
+}
+
+static const struct tty_operations i3c_tty_ops = {
+	.install = i3c_install,
+	.open = i3c_open,
+	.close = i3c_close,
+	.write = i3c_write,
+	.put_char = i3c_put_char,
+	.flush_chars = i3c_flush_chars,
+	.write_room = i3c_write_room,
+	.throttle = i3c_throttle,
+	.unthrottle = i3c_unthrottle,
+	.wait_until_sent = i3c_wait_until_sent,
+};
+
+DECLARE_I3C_SLAVE_FUNC(tty, i3c_tty_probe, i3c_tty_remove, &i3c_func_ops);
+
+static int __init i3c_tty_init(void)
+{
+	int ret;
+
+	i3c_tty_driver = tty_alloc_driver(
+		I3C_TTY_MINORS, TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
+
+	if (IS_ERR(i3c_tty_driver))
+		return PTR_ERR(i3c_tty_driver);
+
+	i3c_tty_driver->driver_name = "ttySI3C", i3c_tty_driver->name = "ttySI3C",
+	i3c_tty_driver->minor_start = 0,
+	i3c_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
+	i3c_tty_driver->subtype = SERIAL_TYPE_NORMAL,
+	i3c_tty_driver->init_termios = tty_std_termios;
+	i3c_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
+					       CLOCAL;
+	i3c_tty_driver->init_termios.c_lflag = 0;
+
+	tty_set_operations(i3c_tty_driver, &i3c_tty_ops);
+
+	ret = tty_register_driver(i3c_tty_driver);
+	if (ret) {
+		tty_driver_kref_put(i3c_tty_driver);
+		return ret;
+	}
+
+	ret = i3c_slave_func_register_driver(&ttyi3c_func);
+	if (ret) {
+		tty_unregister_driver(i3c_tty_driver);
+		tty_driver_kref_put(i3c_tty_driver);
+	}
+
+	return ret;
+}
+
+static void __exit i3c_tty_exit(void)
+{
+	i3c_slave_func_unregister_driver(&ttyi3c_func);
+	tty_unregister_driver(i3c_tty_driver);
+	tty_driver_kref_put(i3c_tty_driver);
+	idr_destroy(&i3c_tty_minors);
+}
+
+module_init(i3c_tty_init);
+module_exit(i3c_tty_exit);
+
+MODULE_LICENSE("GPL");
+
-- 
2.34.1


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

* [PATCH 5/5] Documentation: i3c: Add I3C slave mode controller and function
  2023-10-18 21:58 [PATCH 0/5] I3C slave mode support Frank Li
                   ` (3 preceding siblings ...)
  2023-10-18 21:58 ` [PATCH 4/5] i3c: slave: func: add tty driver Frank Li
@ 2023-10-18 21:58 ` Frank Li
  2023-10-18 22:07   ` Frank Li
  4 siblings, 1 reply; 17+ messages in thread
From: Frank Li @ 2023-10-18 21:58 UTC (permalink / raw)
  To: miquel.raynal, conor.culhane, alexandre.belloni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, joe, Frank.Li,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: gregkh, imx, jirislaby, linux-serial

Add I3C slave mode and tty over i3c func driver document.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 Documentation/driver-api/i3c/index.rst        |   1 +
 .../driver-api/i3c/slave/i3c-slave-cfs.rst    | 109 ++++++++++
 .../driver-api/i3c/slave/i3c-slave.rst        | 189 ++++++++++++++++++
 .../driver-api/i3c/slave/i3c-tty-function.rst | 103 ++++++++++
 .../driver-api/i3c/slave/i3c-tty-howto.rst    | 109 ++++++++++
 Documentation/driver-api/i3c/slave/index.rst  |  13 ++
 6 files changed, 524 insertions(+)
 create mode 100644 Documentation/driver-api/i3c/slave/i3c-slave-cfs.rst
 create mode 100644 Documentation/driver-api/i3c/slave/i3c-slave.rst
 create mode 100644 Documentation/driver-api/i3c/slave/i3c-tty-function.rst
 create mode 100644 Documentation/driver-api/i3c/slave/i3c-tty-howto.rst
 create mode 100644 Documentation/driver-api/i3c/slave/index.rst

diff --git a/Documentation/driver-api/i3c/index.rst b/Documentation/driver-api/i3c/index.rst
index 783d6dad054b6..63fc51fc8bd58 100644
--- a/Documentation/driver-api/i3c/index.rst
+++ b/Documentation/driver-api/i3c/index.rst
@@ -9,3 +9,4 @@ I3C subsystem
    protocol
    device-driver-api
    master-driver-api
+   slave/index
diff --git a/Documentation/driver-api/i3c/slave/i3c-slave-cfs.rst b/Documentation/driver-api/i3c/slave/i3c-slave-cfs.rst
new file mode 100644
index 0000000000000..d78fcbc4e5587
--- /dev/null
+++ b/Documentation/driver-api/i3c/slave/i3c-slave-cfs.rst
@@ -0,0 +1,109 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=======================================
+Configuring I3C Slave Using CONFIGFS
+=======================================
+
+:Author: Frank Li <Frank.Li@nxp.com>
+
+The I3C Slave Core exposes configfs entry (i3c_slave) to configure the I3C
+slave function and to bind the slave function
+with the slave controller. (For introducing other mechanisms to
+configure the I3C Slave Function refer to [1]).
+
+Mounting configfs
+=================
+
+The I3C Slave Core layer creates i3c_slave directory in the mounted configfs
+directory. configfs can be mounted using the following command::
+
+	mount -t configfs none /sys/kernel/config
+
+Directory Structure
+===================
+
+The i3c_slave configfs has two directories at its root: controllers and
+functions. Every Controller device present in the system will have an entry in
+the *controllers* directory and every Function driver present in the system
+will have an entry in the *functions* directory.
+::
+
+	/sys/kernel/config/i3c_slave/
+		.. controllers/
+		.. functions/
+
+Creating Function Device
+===================
+
+Every registered Function driver will be listed in controllers directory. The
+entries corresponding to Function driver will be created by the Function core.
+::
+
+	/sys/kernel/config/i3c_slave/functions/
+		.. <Function Driver1>/
+			... <Function Device 11>/
+			... <Function Device 21>/
+			... <Function Device 31>/
+		.. <Function Driver2>/
+			... <Function Device 12>/
+			... <Function Device 22>/
+
+In order to create a <Function device> of the type probed by <Function Driver>,
+the user has to create a directory inside <Function DriverN>.
+
+Every <Function device> directory consists of the following entries that can be
+used to configure the standard configuration header of the slave function.
+(These entries are created by the framework when any new <Function Device> is
+created)
+::
+
+		.. <Function Driver1>/
+			... <Function Device 11>/
+				... vendor_id
+				... part_id
+				... bcr
+				... dcr
+				... ext_id
+				... instance_id
+				... max_read_len
+				... max_write_len
+				... vendor_info
+
+Controller Device
+==========
+
+Every registered Controller device will be listed in controllers directory. The
+entries corresponding to Controller device will be created by the Controller
+core.
+::
+
+	/sys/kernel/config/i3c_slave/controllers/
+		.. <Controller Device1>/
+			... <Symlink Function Device11>/
+		.. <Controller Device2>/
+			... <Symlink Function Device21>/
+
+The <Controller Device> directory will have a list of symbolic links to
+<Function Device>. These symbolic links should be created by the user to
+represent the functions present in the slave device. Only <Function Device>
+that represents a physical function can be linked to a Controller device.
+
+::
+
+			 | controllers/
+				| <Directory: Controller name>/
+					| <Symbolic Link: Function>
+			 | functions/
+				| <Directory: Function driver>/
+					| <Directory: Function device>/
+						| vendor_id
+						| part_id
+						| bcr
+						| dcr
+						| ext_id
+						| instance_id
+						| max_read_len
+						| max_write_len
+						| vendor_info
+
+[1] Documentation/I3C/slave/pci-slave.rst
diff --git a/Documentation/driver-api/i3c/slave/i3c-slave.rst b/Documentation/driver-api/i3c/slave/i3c-slave.rst
new file mode 100644
index 0000000000000..363421241b594
--- /dev/null
+++ b/Documentation/driver-api/i3c/slave/i3c-slave.rst
@@ -0,0 +1,189 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+:Author: Frank Li <Frank.Li@nxp.com>
+
+This document is a guide to use the I3C Slave Framework in order to create
+slave controller driver, slave function driver, and using configfs
+interface to bind the function driver to the controller driver.
+
+Introduction
+============
+
+Linux has a comprehensive I3C subsystem to support I3C controllers that
+operates in master mode. The subsystem has capability to scan I3C bus,assign
+i3c device address, load I3C driver (based on Manufacturer ID, part ID),
+support other services like hot-join, In-Band Interrupt(IBI).
+
+However the I3C controller IP integrated in some SoCs is capable of operating
+either in Master mode or Slave mode. I3C Slave Framework will add slave mode
+support in Linux. This will help to run Linux in an slave system which can
+have a wide variety of use cases from testing or validation, co-processor
+accelerator, etc.
+
+I3C Slave Core
+=================
+
+The I3C Slave Core layer comprises 3 components: the Slave Controller
+library, the Slave Function library, and the configfs layer to bind the
+slave function with the slave controller.
+
+I3C Slave Controller Library
+------------------------------------
+
+The Controller library provides APIs to be used by the controller that can
+operate in slave mode. It also provides APIs to be used by function
+driver/library in order to implement a particular slave function.
+
+APIs for the I3C Slave controller Driver
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section lists the APIs that the I3C Slave core provides to be used
+by the I3C controller driver.
+
+* devm_i3c_slave_ctrl_create()/i3c_slave_ctrl_create()
+
+   The I3C controller driver should implement the following ops:
+
+	* set_config: ops to set i3c configuration
+	* enable: ops to enable controller
+	* disable: ops to disable controller
+	* raise_ibi: ops to raise IBI to master controller
+	* alloc_request: ops to alloc a transfer request
+	* free_request: ops to free a transfer request
+	* queue: ops to queue a request to transfer queue
+	* dequeue: ops to dequeue a request from transfer queue
+	* cancel_all_reqs: ops to cancel all request from transfer queue
+        * fifo_status: ops to get fifo status
+        * fifo_flush: ops to flush hardware fifo
+	* get_features: ops to get controller supported features
+
+   The I3C controller driver can then create a new Controller device by
+   invoking devm_i3c_slave_ctrl_create()/i3c_slave_ctrl_create().
+
+* devm_i3c_slave_ctrl_destroy()/i3c_slave_ctrl_destroy()
+
+   The I3C controller driver can destroy the Controller device created by
+   either devm_i3c_slave_ctrl_create() or i3c_slave_ctrl_create() using
+   devm_i3c_slave_ctrl_destroy() or i3c_slave_ctrl_destroy().
+
+I3C Slave Controller APIs for the I3C Slave Function Driver
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section lists the APIs that the I3C Slave core provides to be used
+by the I3C slave function driver.
+
+* i3c_slave_ctrl_set_config()
+
+   The I3C slave function driver should use i3c_slave_ctrl_set_config() to
+   write i3c configuration to the slave controller.
+
+* i3c_slave_ctrl_enable()/i3c_slave_ctrl_disable()
+
+   The I3C slave function driver should use i3c_slave_ctrl_enable()/
+   i3c_slave_ctrl_disable() to enable/disable i3c slave controller.
+
+* i3c_slave_ctrl_alloc_request()/i3c_slave_ctrl_free_request()
+
+   The I3C slave function driver should usei3c_slave_ctrl_alloc_request() /
+   i3c_slave_ctrl_free_request() to alloc/free a i3c request.
+
+* i3c_slave_ctrl_raise_ibi()
+
+   The I3C slave function driver should use i3c_slave_ctrl_raise_ibi() to
+   raise IBI.
+
+* i3c_slave_ctrl_queue()/i3c_slave_ctrl_dequeue()
+
+   The I3C slave function driver should use i3c_slave_ctrl_queue()/
+   i3c_slave_ctrl_dequeue(), to queue/dequeue I3C transfer to/from transfer
+   queue.
+
+* i3c_slave_ctrl_get_features()
+
+   The I3C slave function driver should use i3c_slave_ctrl_get_features()
+   to get I3C slave controller supported features.
+
+Other I3C Slave Controller APIs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are other APIs provided by the Controller library. These are used for
+binding the I3C Slave Function device with Controlller device. i3c-cfs.c can
+be used as reference for using these APIs.
+
+* i3c_slave_ctrl_get()
+
+   Get a reference to the I3C slave controller based on the device name of
+   the controller.
+
+* i3c_slave_ctrl_put()
+
+   Release the reference to the I3C slave controller obtained using
+   i3c_slave_ctrl_get()
+
+* i3c_slave_ctrl_add_func()
+
+   Add a I3C slave function to a I3C slave controller.
+
+* i3c_slave_ctrl_remove_func()
+
+   Remove the I3C slave function from I3C slave controller.
+
+I3C Slave Function Library
+----------------------------------
+
+The I3C Slave Function library provides APIs to be used by the function driver
+and the Controller library to provide slave mode functionality.
+
+I3C Slave Function APIs for the I3C Slave Function Driver
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section lists the APIs that the I3C Slave core provides to be used
+by the I3C slave function driver.
+
+* i3c_slave_func_register_driver()
+
+   The I3C Slave Function driver should implement the following ops:
+	 * bind: ops to perform when a Controller device has been bound to
+	   Function device
+	 * unbind: ops to perform when a binding has been lost between a
+	   Controller device and Function device
+
+  The I3C Function driver can then register the I3C Function driver by using
+  i3c_slave_func_register_driver().
+
+* i3c_slave_func_unregister_driver()
+
+  The I3C Function driver can unregister the I3C Function driver by using
+  i3c_epf_unregister_driver().
+
+APIs for the I3C Slave Controller Library
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section lists the APIs that the I3C Slave core provides to be used
+by the I3C slave controller library.
+
+Other I3C Slave APIs
+~~~~~~~~~~~~~~~~~~~~
+
+There are other APIs provided by the Function library. These are used to
+notify the function driver when the Function device is bound to the EPC device.
+i3c-cfs.c can be used as reference for using these APIs.
+
+* i3c_slave_func_create()
+
+   Create a new I3C Function device by passing the name of the I3C EPF device.
+   This name will be used to bind the Function device to a Function driver.
+
+* i3c_slave_func_destroy()
+
+   Destroy the created I3C Function device.
+
+* i3c_slave_func_bind()
+
+   i3c_slave_func_bind() should be invoked when the EPF device has been bound
+   to a Controller device.
+
+* i3c_slave_func_unbind()
+
+   i3c_slave_func_unbind() should be invoked when the binding between EPC
+   device and function device is lost.
diff --git a/Documentation/driver-api/i3c/slave/i3c-tty-function.rst b/Documentation/driver-api/i3c/slave/i3c-tty-function.rst
new file mode 100644
index 0000000000000..3c8521d7aa31a
--- /dev/null
+++ b/Documentation/driver-api/i3c/slave/i3c-tty-function.rst
@@ -0,0 +1,103 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=================
+PCI Test Function
+=================
+
+:Author: Kishon Vijay Abraham I <kishon@ti.com>
+
+Traditionally PCI RC has always been validated by using standard
+PCI cards like ethernet PCI cards or USB PCI cards or SATA PCI cards.
+However with the addition of EP-core in linux kernel, it is possible
+to configure a PCI controller that can operate in EP mode to work as
+a test device.
+
+The PCI endpoint test device is a virtual device (defined in software)
+used to test the endpoint functionality and serve as a sample driver
+for other PCI endpoint devices (to use the EP framework).
+
+The PCI endpoint test device has the following registers:
+
+	1) PCI_ENDPOINT_TEST_MAGIC
+	2) PCI_ENDPOINT_TEST_COMMAND
+	3) PCI_ENDPOINT_TEST_STATUS
+	4) PCI_ENDPOINT_TEST_SRC_ADDR
+	5) PCI_ENDPOINT_TEST_DST_ADDR
+	6) PCI_ENDPOINT_TEST_SIZE
+	7) PCI_ENDPOINT_TEST_CHECKSUM
+	8) PCI_ENDPOINT_TEST_IRQ_TYPE
+	9) PCI_ENDPOINT_TEST_IRQ_NUMBER
+
+* PCI_ENDPOINT_TEST_MAGIC
+
+This register will be used to test BAR0. A known pattern will be written
+and read back from MAGIC register to verify BAR0.
+
+* PCI_ENDPOINT_TEST_COMMAND
+
+This register will be used by the host driver to indicate the function
+that the endpoint device must perform.
+
+========	================================================================
+Bitfield	Description
+========	================================================================
+Bit 0		raise legacy IRQ
+Bit 1		raise MSI IRQ
+Bit 2		raise MSI-X IRQ
+Bit 3		read command (read data from RC buffer)
+Bit 4		write command (write data to RC buffer)
+Bit 5		copy command (copy data from one RC buffer to another RC buffer)
+========	================================================================
+
+* PCI_ENDPOINT_TEST_STATUS
+
+This register reflects the status of the PCI endpoint device.
+
+========	==============================
+Bitfield	Description
+========	==============================
+Bit 0		read success
+Bit 1		read fail
+Bit 2		write success
+Bit 3		write fail
+Bit 4		copy success
+Bit 5		copy fail
+Bit 6		IRQ raised
+Bit 7		source address is invalid
+Bit 8		destination address is invalid
+========	==============================
+
+* PCI_ENDPOINT_TEST_SRC_ADDR
+
+This register contains the source address (RC buffer address) for the
+COPY/READ command.
+
+* PCI_ENDPOINT_TEST_DST_ADDR
+
+This register contains the destination address (RC buffer address) for
+the COPY/WRITE command.
+
+* PCI_ENDPOINT_TEST_IRQ_TYPE
+
+This register contains the interrupt type (Legacy/MSI) triggered
+for the READ/WRITE/COPY and raise IRQ (Legacy/MSI) commands.
+
+Possible types:
+
+======	==
+Legacy	0
+MSI	1
+MSI-X	2
+======	==
+
+* PCI_ENDPOINT_TEST_IRQ_NUMBER
+
+This register contains the triggered ID interrupt.
+
+Admissible values:
+
+======	===========
+Legacy	0
+MSI	[1 .. 32]
+MSI-X	[1 .. 2048]
+======	===========
diff --git a/Documentation/driver-api/i3c/slave/i3c-tty-howto.rst b/Documentation/driver-api/i3c/slave/i3c-tty-howto.rst
new file mode 100644
index 0000000000000..11c8900fd16f3
--- /dev/null
+++ b/Documentation/driver-api/i3c/slave/i3c-tty-howto.rst
@@ -0,0 +1,109 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===================
+I3C TTY User Guide
+===================
+
+:Author: Frank Li <Frank.Li@nxp.com>
+
+This document is a guide to help users use i3c-slave-tty function driver
+and i3ctty master driver for testing I3C. The list of steps to be followed in the
+master side and slave side is given below.
+
+Endpoint Device
+===============
+
+Endpoint Controller Devices
+---------------------------
+
+To find the list of slave controller devices in the system::
+
+	# ls  /sys/class/i3c_slave/
+	  44330000.i3c-slave
+
+If CONFIG_I3C_SLAVE_CONFIGFS is enabled::
+
+	# ls /sys/kernel/config/i3c_slave/controllers/
+	  44330000.i3c-slave
+
+
+Endpoint Function Drivers
+-------------------------
+
+To find the list of slave function drivers in the system::
+
+	# ls /sys/bus/i3c_slave_func/drivers
+	  tty
+
+If CONFIG_I3C_SLAVE_CONFIGFS is enabled::
+
+	# ls /sys/kernel/config/i3c_slave/functions
+	  tty
+
+
+Creating i3c-slave-tty Device
+----------------------------
+
+I3C slave function device can be created using the configfs. To create
+i3c-slave-tty device, the following commands can be used::
+
+	# mount -t configfs none /sys/kernel/config
+	# cd /sys/kernel/config/i3c_slave/
+	# mkdir functions/tty/func1
+
+The "mkdir func1" above creates the i3c-slave-tty function device that will
+be probed by i3c tty driver.
+
+The I3C slave framework populates the directory with the following
+configurable fields::
+
+	# ls functions/tty/func1
+	bcr  dcr  ext_id  instance_id  max_read_len  max_write_len
+	part_id  vendor_id  vendor_info
+
+The I3C slave function driver populates these entries with default values
+when the device is bound to the driver. The i3c-slave-tty driver populates
+vendorid with 0xffff and interrupt_pin with 0x0001::
+
+	# cat functions/tty/func1/vendor_id
+	  0x0
+
+Configuring i3c-slave-tty Device
+-------------------------------
+
+The user can configure the i3c-slave-tty device using configfs entry. In order
+to change the vendorid, the following commands can be used::
+
+	# echo 0x011b > functions/tty/func1/vendor_id
+	# echo 0x1000 > functions/tty/func1/part_id
+	# echo 0x6 > functions/tty/t/bcr
+
+Binding i3c-slave-tty Device to slave Controller
+------------------------------------------------
+
+In order for the slave function device to be useful, it has to be bound to
+a I3C slave controller driver. Use the configfs to bind the function
+device to one of the controller driver present in the system::
+
+	# ln -s functions/pci_epf_test/func1 controllers/44330000.i3c-slave/
+
+I3C Master Device
+================
+
+Check I3C tty device is probed
+
+	# ls /sys/bus/i3c/devices/0-23610000000
+	0-23610000000:0  bcr  dcr  driver  dynamic_address  hdrcap
+	modalias  pid  power  subsystem  tty  uevent
+
+Using Slave TTY function Device
+-----------------------------------
+
+Host side:
+	cat /dev/ttyI3C0
+Slave side
+	echo abc >/dev/ttyI3C0
+
+You will see "abc" show at console.
+
+You can use other tty tool to test I3C slave tty device.
diff --git a/Documentation/driver-api/i3c/slave/index.rst b/Documentation/driver-api/i3c/slave/index.rst
new file mode 100644
index 0000000000000..69727ccf985db
--- /dev/null
+++ b/Documentation/driver-api/i3c/slave/index.rst
@@ -0,0 +1,13 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================
+I3C Slave Framework
+======================
+
+.. toctree::
+   :maxdepth: 2
+
+   i3c-slave
+   i3c-slave-cfs
+   i3c-tty-howto
+
-- 
2.34.1


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

* Re: [PATCH 5/5] Documentation: i3c: Add I3C slave mode controller and function
  2023-10-18 21:58 ` [PATCH 5/5] Documentation: i3c: Add I3C slave mode controller and function Frank Li
@ 2023-10-18 22:07   ` Frank Li
  0 siblings, 0 replies; 17+ messages in thread
From: Frank Li @ 2023-10-18 22:07 UTC (permalink / raw)
  To: miquel.raynal, conor.culhane, alexandre.belloni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, joe, linux-i3c,
	devicetree, linux-kernel, linux-doc
  Cc: gregkh, imx, jirislaby, linux-serial

On Wed, Oct 18, 2023 at 05:58:09PM -0400, Frank Li wrote:
> Add I3C slave mode and tty over i3c func driver document.
> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
>  Documentation/driver-api/i3c/index.rst        |   1 +
>  .../driver-api/i3c/slave/i3c-slave-cfs.rst    | 109 ++++++++++
>  .../driver-api/i3c/slave/i3c-slave.rst        | 189 ++++++++++++++++++
>  .../driver-api/i3c/slave/i3c-tty-function.rst | 103 ++++++++++
>  .../driver-api/i3c/slave/i3c-tty-howto.rst    | 109 ++++++++++
>  Documentation/driver-api/i3c/slave/index.rst  |  13 ++
>  6 files changed, 524 insertions(+)
>  create mode 100644 Documentation/driver-api/i3c/slave/i3c-slave-cfs.rst
>  create mode 100644 Documentation/driver-api/i3c/slave/i3c-slave.rst
>  create mode 100644 Documentation/driver-api/i3c/slave/i3c-tty-function.rst

Please omit i3c-tty-function.rst. This one accidently add to here.
I will remove it at next version.

>  create mode 100644 Documentation/driver-api/i3c/slave/i3c-tty-howto.rst
>  create mode 100644 Documentation/driver-api/i3c/slave/index.rst
> 
> diff --git a/Documentation/driver-api/i3c/index.rst b/Documentation/driver-api/i3c/index.rst
> index 783d6dad054b6..63fc51fc8bd58 100644
> --- a/Documentation/driver-api/i3c/index.rst
> +++ b/Documentation/driver-api/i3c/index.rst
> @@ -9,3 +9,4 @@ I3C subsystem
>     protocol
>     device-driver-api
>     master-driver-api
> +   slave/index
> diff --git a/Documentation/driver-api/i3c/slave/i3c-slave-cfs.rst b/Documentation/driver-api/i3c/slave/i3c-slave-cfs.rst
> new file mode 100644
> index 0000000000000..d78fcbc4e5587
> --- /dev/null
> +++ b/Documentation/driver-api/i3c/slave/i3c-slave-cfs.rst
> @@ -0,0 +1,109 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +=======================================
> +Configuring I3C Slave Using CONFIGFS
> +=======================================
> +
> +:Author: Frank Li <Frank.Li@nxp.com>
> +
> +The I3C Slave Core exposes configfs entry (i3c_slave) to configure the I3C
> +slave function and to bind the slave function
> +with the slave controller. (For introducing other mechanisms to
> +configure the I3C Slave Function refer to [1]).
> +
> +Mounting configfs
> +=================
> +
> +The I3C Slave Core layer creates i3c_slave directory in the mounted configfs
> +directory. configfs can be mounted using the following command::
> +
> +	mount -t configfs none /sys/kernel/config
> +
> +Directory Structure
> +===================
> +
> +The i3c_slave configfs has two directories at its root: controllers and
> +functions. Every Controller device present in the system will have an entry in
> +the *controllers* directory and every Function driver present in the system
> +will have an entry in the *functions* directory.
> +::
> +
> +	/sys/kernel/config/i3c_slave/
> +		.. controllers/
> +		.. functions/
> +
> +Creating Function Device
> +===================
> +
> +Every registered Function driver will be listed in controllers directory. The
> +entries corresponding to Function driver will be created by the Function core.
> +::
> +
> +	/sys/kernel/config/i3c_slave/functions/
> +		.. <Function Driver1>/
> +			... <Function Device 11>/
> +			... <Function Device 21>/
> +			... <Function Device 31>/
> +		.. <Function Driver2>/
> +			... <Function Device 12>/
> +			... <Function Device 22>/
> +
> +In order to create a <Function device> of the type probed by <Function Driver>,
> +the user has to create a directory inside <Function DriverN>.
> +
> +Every <Function device> directory consists of the following entries that can be
> +used to configure the standard configuration header of the slave function.
> +(These entries are created by the framework when any new <Function Device> is
> +created)
> +::
> +
> +		.. <Function Driver1>/
> +			... <Function Device 11>/
> +				... vendor_id
> +				... part_id
> +				... bcr
> +				... dcr
> +				... ext_id
> +				... instance_id
> +				... max_read_len
> +				... max_write_len
> +				... vendor_info
> +
> +Controller Device
> +==========
> +
> +Every registered Controller device will be listed in controllers directory. The
> +entries corresponding to Controller device will be created by the Controller
> +core.
> +::
> +
> +	/sys/kernel/config/i3c_slave/controllers/
> +		.. <Controller Device1>/
> +			... <Symlink Function Device11>/
> +		.. <Controller Device2>/
> +			... <Symlink Function Device21>/
> +
> +The <Controller Device> directory will have a list of symbolic links to
> +<Function Device>. These symbolic links should be created by the user to
> +represent the functions present in the slave device. Only <Function Device>
> +that represents a physical function can be linked to a Controller device.
> +
> +::
> +
> +			 | controllers/
> +				| <Directory: Controller name>/
> +					| <Symbolic Link: Function>
> +			 | functions/
> +				| <Directory: Function driver>/
> +					| <Directory: Function device>/
> +						| vendor_id
> +						| part_id
> +						| bcr
> +						| dcr
> +						| ext_id
> +						| instance_id
> +						| max_read_len
> +						| max_write_len
> +						| vendor_info
> +
> +[1] Documentation/I3C/slave/pci-slave.rst
> diff --git a/Documentation/driver-api/i3c/slave/i3c-slave.rst b/Documentation/driver-api/i3c/slave/i3c-slave.rst
> new file mode 100644
> index 0000000000000..363421241b594
> --- /dev/null
> +++ b/Documentation/driver-api/i3c/slave/i3c-slave.rst
> @@ -0,0 +1,189 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +:Author: Frank Li <Frank.Li@nxp.com>
> +
> +This document is a guide to use the I3C Slave Framework in order to create
> +slave controller driver, slave function driver, and using configfs
> +interface to bind the function driver to the controller driver.
> +
> +Introduction
> +============
> +
> +Linux has a comprehensive I3C subsystem to support I3C controllers that
> +operates in master mode. The subsystem has capability to scan I3C bus,assign
> +i3c device address, load I3C driver (based on Manufacturer ID, part ID),
> +support other services like hot-join, In-Band Interrupt(IBI).
> +
> +However the I3C controller IP integrated in some SoCs is capable of operating
> +either in Master mode or Slave mode. I3C Slave Framework will add slave mode
> +support in Linux. This will help to run Linux in an slave system which can
> +have a wide variety of use cases from testing or validation, co-processor
> +accelerator, etc.
> +
> +I3C Slave Core
> +=================
> +
> +The I3C Slave Core layer comprises 3 components: the Slave Controller
> +library, the Slave Function library, and the configfs layer to bind the
> +slave function with the slave controller.
> +
> +I3C Slave Controller Library
> +------------------------------------
> +
> +The Controller library provides APIs to be used by the controller that can
> +operate in slave mode. It also provides APIs to be used by function
> +driver/library in order to implement a particular slave function.
> +
> +APIs for the I3C Slave controller Driver
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +This section lists the APIs that the I3C Slave core provides to be used
> +by the I3C controller driver.
> +
> +* devm_i3c_slave_ctrl_create()/i3c_slave_ctrl_create()
> +
> +   The I3C controller driver should implement the following ops:
> +
> +	* set_config: ops to set i3c configuration
> +	* enable: ops to enable controller
> +	* disable: ops to disable controller
> +	* raise_ibi: ops to raise IBI to master controller
> +	* alloc_request: ops to alloc a transfer request
> +	* free_request: ops to free a transfer request
> +	* queue: ops to queue a request to transfer queue
> +	* dequeue: ops to dequeue a request from transfer queue
> +	* cancel_all_reqs: ops to cancel all request from transfer queue
> +        * fifo_status: ops to get fifo status
> +        * fifo_flush: ops to flush hardware fifo
> +	* get_features: ops to get controller supported features
> +
> +   The I3C controller driver can then create a new Controller device by
> +   invoking devm_i3c_slave_ctrl_create()/i3c_slave_ctrl_create().
> +
> +* devm_i3c_slave_ctrl_destroy()/i3c_slave_ctrl_destroy()
> +
> +   The I3C controller driver can destroy the Controller device created by
> +   either devm_i3c_slave_ctrl_create() or i3c_slave_ctrl_create() using
> +   devm_i3c_slave_ctrl_destroy() or i3c_slave_ctrl_destroy().
> +
> +I3C Slave Controller APIs for the I3C Slave Function Driver
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +This section lists the APIs that the I3C Slave core provides to be used
> +by the I3C slave function driver.
> +
> +* i3c_slave_ctrl_set_config()
> +
> +   The I3C slave function driver should use i3c_slave_ctrl_set_config() to
> +   write i3c configuration to the slave controller.
> +
> +* i3c_slave_ctrl_enable()/i3c_slave_ctrl_disable()
> +
> +   The I3C slave function driver should use i3c_slave_ctrl_enable()/
> +   i3c_slave_ctrl_disable() to enable/disable i3c slave controller.
> +
> +* i3c_slave_ctrl_alloc_request()/i3c_slave_ctrl_free_request()
> +
> +   The I3C slave function driver should usei3c_slave_ctrl_alloc_request() /
> +   i3c_slave_ctrl_free_request() to alloc/free a i3c request.
> +
> +* i3c_slave_ctrl_raise_ibi()
> +
> +   The I3C slave function driver should use i3c_slave_ctrl_raise_ibi() to
> +   raise IBI.
> +
> +* i3c_slave_ctrl_queue()/i3c_slave_ctrl_dequeue()
> +
> +   The I3C slave function driver should use i3c_slave_ctrl_queue()/
> +   i3c_slave_ctrl_dequeue(), to queue/dequeue I3C transfer to/from transfer
> +   queue.
> +
> +* i3c_slave_ctrl_get_features()
> +
> +   The I3C slave function driver should use i3c_slave_ctrl_get_features()
> +   to get I3C slave controller supported features.
> +
> +Other I3C Slave Controller APIs
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +There are other APIs provided by the Controller library. These are used for
> +binding the I3C Slave Function device with Controlller device. i3c-cfs.c can
> +be used as reference for using these APIs.
> +
> +* i3c_slave_ctrl_get()
> +
> +   Get a reference to the I3C slave controller based on the device name of
> +   the controller.
> +
> +* i3c_slave_ctrl_put()
> +
> +   Release the reference to the I3C slave controller obtained using
> +   i3c_slave_ctrl_get()
> +
> +* i3c_slave_ctrl_add_func()
> +
> +   Add a I3C slave function to a I3C slave controller.
> +
> +* i3c_slave_ctrl_remove_func()
> +
> +   Remove the I3C slave function from I3C slave controller.
> +
> +I3C Slave Function Library
> +----------------------------------
> +
> +The I3C Slave Function library provides APIs to be used by the function driver
> +and the Controller library to provide slave mode functionality.
> +
> +I3C Slave Function APIs for the I3C Slave Function Driver
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +This section lists the APIs that the I3C Slave core provides to be used
> +by the I3C slave function driver.
> +
> +* i3c_slave_func_register_driver()
> +
> +   The I3C Slave Function driver should implement the following ops:
> +	 * bind: ops to perform when a Controller device has been bound to
> +	   Function device
> +	 * unbind: ops to perform when a binding has been lost between a
> +	   Controller device and Function device
> +
> +  The I3C Function driver can then register the I3C Function driver by using
> +  i3c_slave_func_register_driver().
> +
> +* i3c_slave_func_unregister_driver()
> +
> +  The I3C Function driver can unregister the I3C Function driver by using
> +  i3c_epf_unregister_driver().
> +
> +APIs for the I3C Slave Controller Library
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +This section lists the APIs that the I3C Slave core provides to be used
> +by the I3C slave controller library.
> +
> +Other I3C Slave APIs
> +~~~~~~~~~~~~~~~~~~~~
> +
> +There are other APIs provided by the Function library. These are used to
> +notify the function driver when the Function device is bound to the EPC device.
> +i3c-cfs.c can be used as reference for using these APIs.
> +
> +* i3c_slave_func_create()
> +
> +   Create a new I3C Function device by passing the name of the I3C EPF device.
> +   This name will be used to bind the Function device to a Function driver.
> +
> +* i3c_slave_func_destroy()
> +
> +   Destroy the created I3C Function device.
> +
> +* i3c_slave_func_bind()
> +
> +   i3c_slave_func_bind() should be invoked when the EPF device has been bound
> +   to a Controller device.
> +
> +* i3c_slave_func_unbind()
> +
> +   i3c_slave_func_unbind() should be invoked when the binding between EPC
> +   device and function device is lost.
> diff --git a/Documentation/driver-api/i3c/slave/i3c-tty-function.rst b/Documentation/driver-api/i3c/slave/i3c-tty-function.rst
> new file mode 100644
> index 0000000000000..3c8521d7aa31a
> --- /dev/null
> +++ b/Documentation/driver-api/i3c/slave/i3c-tty-function.rst
> @@ -0,0 +1,103 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +=================
> +PCI Test Function
> +=================
> +
> +:Author: Kishon Vijay Abraham I <kishon@ti.com>
> +
> +Traditionally PCI RC has always been validated by using standard
> +PCI cards like ethernet PCI cards or USB PCI cards or SATA PCI cards.
> +However with the addition of EP-core in linux kernel, it is possible
> +to configure a PCI controller that can operate in EP mode to work as
> +a test device.
> +
> +The PCI endpoint test device is a virtual device (defined in software)
> +used to test the endpoint functionality and serve as a sample driver
> +for other PCI endpoint devices (to use the EP framework).
> +
> +The PCI endpoint test device has the following registers:
> +
> +	1) PCI_ENDPOINT_TEST_MAGIC
> +	2) PCI_ENDPOINT_TEST_COMMAND
> +	3) PCI_ENDPOINT_TEST_STATUS
> +	4) PCI_ENDPOINT_TEST_SRC_ADDR
> +	5) PCI_ENDPOINT_TEST_DST_ADDR
> +	6) PCI_ENDPOINT_TEST_SIZE
> +	7) PCI_ENDPOINT_TEST_CHECKSUM
> +	8) PCI_ENDPOINT_TEST_IRQ_TYPE
> +	9) PCI_ENDPOINT_TEST_IRQ_NUMBER
> +
> +* PCI_ENDPOINT_TEST_MAGIC
> +
> +This register will be used to test BAR0. A known pattern will be written
> +and read back from MAGIC register to verify BAR0.
> +
> +* PCI_ENDPOINT_TEST_COMMAND
> +
> +This register will be used by the host driver to indicate the function
> +that the endpoint device must perform.
> +
> +========	================================================================
> +Bitfield	Description
> +========	================================================================
> +Bit 0		raise legacy IRQ
> +Bit 1		raise MSI IRQ
> +Bit 2		raise MSI-X IRQ
> +Bit 3		read command (read data from RC buffer)
> +Bit 4		write command (write data to RC buffer)
> +Bit 5		copy command (copy data from one RC buffer to another RC buffer)
> +========	================================================================
> +
> +* PCI_ENDPOINT_TEST_STATUS
> +
> +This register reflects the status of the PCI endpoint device.
> +
> +========	==============================
> +Bitfield	Description
> +========	==============================
> +Bit 0		read success
> +Bit 1		read fail
> +Bit 2		write success
> +Bit 3		write fail
> +Bit 4		copy success
> +Bit 5		copy fail
> +Bit 6		IRQ raised
> +Bit 7		source address is invalid
> +Bit 8		destination address is invalid
> +========	==============================
> +
> +* PCI_ENDPOINT_TEST_SRC_ADDR
> +
> +This register contains the source address (RC buffer address) for the
> +COPY/READ command.
> +
> +* PCI_ENDPOINT_TEST_DST_ADDR
> +
> +This register contains the destination address (RC buffer address) for
> +the COPY/WRITE command.
> +
> +* PCI_ENDPOINT_TEST_IRQ_TYPE
> +
> +This register contains the interrupt type (Legacy/MSI) triggered
> +for the READ/WRITE/COPY and raise IRQ (Legacy/MSI) commands.
> +
> +Possible types:
> +
> +======	==
> +Legacy	0
> +MSI	1
> +MSI-X	2
> +======	==
> +
> +* PCI_ENDPOINT_TEST_IRQ_NUMBER
> +
> +This register contains the triggered ID interrupt.
> +
> +Admissible values:
> +
> +======	===========
> +Legacy	0
> +MSI	[1 .. 32]
> +MSI-X	[1 .. 2048]
> +======	===========
> diff --git a/Documentation/driver-api/i3c/slave/i3c-tty-howto.rst b/Documentation/driver-api/i3c/slave/i3c-tty-howto.rst
> new file mode 100644
> index 0000000000000..11c8900fd16f3
> --- /dev/null
> +++ b/Documentation/driver-api/i3c/slave/i3c-tty-howto.rst
> @@ -0,0 +1,109 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +===================
> +I3C TTY User Guide
> +===================
> +
> +:Author: Frank Li <Frank.Li@nxp.com>
> +
> +This document is a guide to help users use i3c-slave-tty function driver
> +and i3ctty master driver for testing I3C. The list of steps to be followed in the
> +master side and slave side is given below.
> +
> +Endpoint Device
> +===============
> +
> +Endpoint Controller Devices
> +---------------------------
> +
> +To find the list of slave controller devices in the system::
> +
> +	# ls  /sys/class/i3c_slave/
> +	  44330000.i3c-slave
> +
> +If CONFIG_I3C_SLAVE_CONFIGFS is enabled::
> +
> +	# ls /sys/kernel/config/i3c_slave/controllers/
> +	  44330000.i3c-slave
> +
> +
> +Endpoint Function Drivers
> +-------------------------
> +
> +To find the list of slave function drivers in the system::
> +
> +	# ls /sys/bus/i3c_slave_func/drivers
> +	  tty
> +
> +If CONFIG_I3C_SLAVE_CONFIGFS is enabled::
> +
> +	# ls /sys/kernel/config/i3c_slave/functions
> +	  tty
> +
> +
> +Creating i3c-slave-tty Device
> +----------------------------
> +
> +I3C slave function device can be created using the configfs. To create
> +i3c-slave-tty device, the following commands can be used::
> +
> +	# mount -t configfs none /sys/kernel/config
> +	# cd /sys/kernel/config/i3c_slave/
> +	# mkdir functions/tty/func1
> +
> +The "mkdir func1" above creates the i3c-slave-tty function device that will
> +be probed by i3c tty driver.
> +
> +The I3C slave framework populates the directory with the following
> +configurable fields::
> +
> +	# ls functions/tty/func1
> +	bcr  dcr  ext_id  instance_id  max_read_len  max_write_len
> +	part_id  vendor_id  vendor_info
> +
> +The I3C slave function driver populates these entries with default values
> +when the device is bound to the driver. The i3c-slave-tty driver populates
> +vendorid with 0xffff and interrupt_pin with 0x0001::
> +
> +	# cat functions/tty/func1/vendor_id
> +	  0x0
> +
> +Configuring i3c-slave-tty Device
> +-------------------------------
> +
> +The user can configure the i3c-slave-tty device using configfs entry. In order
> +to change the vendorid, the following commands can be used::
> +
> +	# echo 0x011b > functions/tty/func1/vendor_id
> +	# echo 0x1000 > functions/tty/func1/part_id
> +	# echo 0x6 > functions/tty/t/bcr
> +
> +Binding i3c-slave-tty Device to slave Controller
> +------------------------------------------------
> +
> +In order for the slave function device to be useful, it has to be bound to
> +a I3C slave controller driver. Use the configfs to bind the function
> +device to one of the controller driver present in the system::
> +
> +	# ln -s functions/pci_epf_test/func1 controllers/44330000.i3c-slave/
> +
> +I3C Master Device
> +================
> +
> +Check I3C tty device is probed
> +
> +	# ls /sys/bus/i3c/devices/0-23610000000
> +	0-23610000000:0  bcr  dcr  driver  dynamic_address  hdrcap
> +	modalias  pid  power  subsystem  tty  uevent
> +
> +Using Slave TTY function Device
> +-----------------------------------
> +
> +Host side:
> +	cat /dev/ttyI3C0
> +Slave side
> +	echo abc >/dev/ttyI3C0
> +
> +You will see "abc" show at console.
> +
> +You can use other tty tool to test I3C slave tty device.
> diff --git a/Documentation/driver-api/i3c/slave/index.rst b/Documentation/driver-api/i3c/slave/index.rst
> new file mode 100644
> index 0000000000000..69727ccf985db
> --- /dev/null
> +++ b/Documentation/driver-api/i3c/slave/index.rst
> @@ -0,0 +1,13 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +======================
> +I3C Slave Framework
> +======================
> +
> +.. toctree::
> +   :maxdepth: 2
> +
> +   i3c-slave
> +   i3c-slave-cfs
> +   i3c-tty-howto
> +
> -- 
> 2.34.1
> 

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

* Re: [PATCH 1/5] i3c: add slave mode support
  2023-10-18 21:58 ` [PATCH 1/5] i3c: add " Frank Li
@ 2023-10-19  7:00   ` Krzysztof Kozlowski
  2023-10-19 15:02     ` Frank Li
  2023-10-23  1:11   ` kernel test robot
  2023-10-23  1:20   ` kernel test robot
  2 siblings, 1 reply; 17+ messages in thread
From: Krzysztof Kozlowski @ 2023-10-19  7:00 UTC (permalink / raw)
  To: Frank Li, miquel.raynal, conor.culhane, alexandre.belloni,
	robh+dt, krzysztof.kozlowski+dt, conor+dt, corbet, joe,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: gregkh, imx, jirislaby, linux-serial

On 18/10/2023 23:58, Frank Li wrote:
> Introduce a new slave core layer in order to support slave functions in
> linux kernel. This comprises the controller library and function library.
> Controller library implements functions specific to an slave controller
> and function library implements functions specific to an slave function.
> 
> Introduce a new configfs entry to configure the slave function configuring
> and bind the slave function with slave controller.
> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
>  drivers/i3c/Kconfig       |  26 ++
>  drivers/i3c/Makefile      |   2 +
>  drivers/i3c/i3c-cfs.c     | 389 +++++++++++++++++++++++++++++
>  drivers/i3c/slave.c       | 453 ++++++++++++++++++++++++++++++++++
>  include/linux/i3c/slave.h | 503 ++++++++++++++++++++++++++++++++++++++
>  5 files changed, 1373 insertions(+)
>  create mode 100644 drivers/i3c/i3c-cfs.c
>  create mode 100644 drivers/i3c/slave.c
>  create mode 100644 include/linux/i3c/slave.h
> 
> diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig
> index 30a441506f61c..d5f5ca7cd6a56 100644
> --- a/drivers/i3c/Kconfig
> +++ b/drivers/i3c/Kconfig
> @@ -22,3 +22,29 @@ menuconfig I3C
>  if I3C
>  source "drivers/i3c/master/Kconfig"
>  endif # I3C
> +
> +config I3C_SLAVE

It doesn't look like you follow Kernel naming convention (see coding style).

> +	bool "I3C Slave Support"
> +	help
> +	  Support I3C Slave Mode.
> +



Best regards,
Krzysztof


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

* Re: [PATCH 2/5] dt-bindings: i3c: svc: add compatible string i3c: silvaco,i3c-slave
  2023-10-18 21:58 ` [PATCH 2/5] dt-bindings: i3c: svc: add compatible string i3c: silvaco,i3c-slave Frank Li
@ 2023-10-19  7:00   ` Krzysztof Kozlowski
  2023-10-19 12:07   ` Rob Herring
  1 sibling, 0 replies; 17+ messages in thread
From: Krzysztof Kozlowski @ 2023-10-19  7:00 UTC (permalink / raw)
  To: Frank Li, miquel.raynal, conor.culhane, alexandre.belloni,
	robh+dt, krzysztof.kozlowski+dt, conor+dt, corbet, joe,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: gregkh, imx, jirislaby, linux-serial

On 18/10/2023 23:58, Frank Li wrote:
> Add compatible string 'silvaco,i3c-slave' for slave mode.
> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
>  .../devicetree/bindings/i3c/silvaco,i3c-master.yaml       | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml
> index 133855f11b4f5..63db63f00a509 100644
> --- a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml
> +++ b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml
> @@ -4,7 +4,7 @@
>  $id: http://devicetree.org/schemas/i3c/silvaco,i3c-master.yaml#
>  $schema: http://devicetree.org/meta-schemas/core.yaml#
>  
> -title: Silvaco I3C master
> +title: Silvaco I3C master/slave
>  
>  maintainers:
>    - Conor Culhane <conor.culhane@silvaco.com>
> @@ -14,8 +14,10 @@ allOf:
>  
>  properties:
>    compatible:
> -    const: silvaco,i3c-master-v1
> -
> +    const:
> +      enum:
> +        - silvaco,i3c-master-v1
> +        - silvaco,i3c-slave-v1

Missing blank line.

Rather choose name from Coding style.

Best regards,
Krzysztof


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

* Re: [PATCH 4/5] i3c: slave: func: add tty driver
  2023-10-18 21:58 ` [PATCH 4/5] i3c: slave: func: add tty driver Frank Li
@ 2023-10-19  7:21   ` Jiri Slaby
  0 siblings, 0 replies; 17+ messages in thread
From: Jiri Slaby @ 2023-10-19  7:21 UTC (permalink / raw)
  To: Frank Li, miquel.raynal, conor.culhane, alexandre.belloni,
	robh+dt, krzysztof.kozlowski+dt, conor+dt, corbet, joe,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: gregkh, imx, linux-serial

On 18. 10. 23, 23:58, Frank Li wrote:
> Add tty over I3C slave function driver.

Many of the master review comments apply also here. Please fix here too. 
More below.

> --- /dev/null
> +++ b/drivers/i3c/func/tty.c
> @@ -0,0 +1,548 @@
...
> +static void i3c_slave_tty_rx_complete(struct i3c_request *req)
> +{
> +	struct ttyi3c_port *port = req->context;
> +
> +	if (req->status == I3C_REQUEST_CANCEL) {
> +		i3c_slave_ctrl_free_request(req);
> +		return;
> +	}
> +
> +	for (int i = 0; i < req->actual; i++)
> +		tty_insert_flip_char(&port->port, *(u8 *)(req->buf + i), 0);

Maybe I miss something obvious, but req->buf is void *. So why not 
simple tty_insert_flip_string()?


> +	sport->buffer = (void *)get_zeroed_page(GFP_KERNEL);
> +	if (!sport->buffer)
> +		return -ENOMEM;
> +
> +	sport->xmit.buf = (void *)get_zeroed_page(GFP_KERNEL);

tty_port_alloc_xmit_buf()


> +static int i3c_tty_probe(struct i3c_slave_func *func)
> +{
> +	struct device *dev = &func->dev;
> +	struct ttyi3c_port *port;
> +
> +	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> +	if (!port)
> +		return -ENOMEM;
> +
> +	port->i3cdev = func;
> +	dev_set_drvdata(&func->dev, port);
> +
> +	port->workqueue = alloc_workqueue("%s", 0, 0, dev_name(&func->dev));

Another wq? You'd have to have a strong reason for these. Drop that.

> +	if (!port->workqueue)
> +		return -ENOMEM;
> +
> +	INIT_WORK(&port->work, i3c_slave_tty_i3c_work);
> +
> +	return 0;
> +}
> +
> +static void  i3c_tty_remove(struct i3c_slave_func *func)
> +{
> +	struct ttyi3c_port *port;
> +
> +	port = dev_get_drvdata(&func->dev);

That can be on one line.

> +
> +	destroy_workqueue(port->workqueue);
> +}


> +static int i3c_open(struct tty_struct *tty, struct file *filp)
> +{
> +	struct ttyi3c_port *sport = tty->driver_data;
> +	int ret;
> +
> +	if (!i3c_slave_ctrl_get_addr(sport->i3cdev->ctrl)) {
> +		dev_info(&sport->i3cdev->dev, "No slave addr assigned, try hotjoin");

Should this be a debug print instead?

> +		ret = i3c_slave_ctrl_hotjoin(sport->i3cdev->ctrl);
> +		if (ret) {
> +			dev_err(&sport->i3cdev->dev, "Hotjoin failure, check connection");
> +			return ret;
> +		}
> +	}
> +
> +	return tty_port_open(&sport->port, tty, filp);

regards,
-- 
js
suse labs


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

* Re: [PATCH 2/5] dt-bindings: i3c: svc: add compatible string i3c: silvaco,i3c-slave
  2023-10-18 21:58 ` [PATCH 2/5] dt-bindings: i3c: svc: add compatible string i3c: silvaco,i3c-slave Frank Li
  2023-10-19  7:00   ` Krzysztof Kozlowski
@ 2023-10-19 12:07   ` Rob Herring
  1 sibling, 0 replies; 17+ messages in thread
From: Rob Herring @ 2023-10-19 12:07 UTC (permalink / raw)
  To: Frank Li
  Cc: gregkh, linux-doc, conor.culhane, conor+dt, linux-kernel,
	devicetree, alexandre.belloni, imx, linux-i3c, jirislaby,
	krzysztof.kozlowski+dt, miquel.raynal, linux-serial, robh+dt,
	corbet, joe


On Wed, 18 Oct 2023 17:58:06 -0400, Frank Li wrote:
> Add compatible string 'silvaco,i3c-slave' for slave mode.
> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
>  .../devicetree/bindings/i3c/silvaco,i3c-master.yaml       | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml: properties:compatible:const: {'enum': ['silvaco,i3c-master-v1', 'silvaco,i3c-slave-v1']} is not of type 'integer', 'string'
	from schema $id: http://devicetree.org/meta-schemas/keywords.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml: properties:compatible:const: {'enum': ['silvaco,i3c-master-v1', 'silvaco,i3c-slave-v1']} is not of type 'string'
	from schema $id: http://devicetree.org/meta-schemas/string-array.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.example.dtb: i3c-master@a0000000: compatible: {'enum': ['silvaco,i3c-master-v1', 'silvaco,i3c-slave-v1']} was expected
	from schema $id: http://devicetree.org/schemas/i3c/silvaco,i3c-master.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.example.dtb: i3c-master@a0000000: Unevaluated properties are not allowed ('compatible' was unexpected)
	from schema $id: http://devicetree.org/schemas/i3c/silvaco,i3c-master.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20231018215809.3477437-3-Frank.Li@nxp.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


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

* Re: [PATCH 1/5] i3c: add slave mode support
  2023-10-19  7:00   ` Krzysztof Kozlowski
@ 2023-10-19 15:02     ` Frank Li
  2023-10-19 15:46       ` Greg KH
  0 siblings, 1 reply; 17+ messages in thread
From: Frank Li @ 2023-10-19 15:02 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: miquel.raynal, conor.culhane, alexandre.belloni, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, corbet, joe, linux-i3c,
	devicetree, linux-kernel, linux-doc, gregkh, imx, jirislaby,
	linux-serial

On Thu, Oct 19, 2023 at 09:00:05AM +0200, Krzysztof Kozlowski wrote:
> On 18/10/2023 23:58, Frank Li wrote:
> > Introduce a new slave core layer in order to support slave functions in
> > linux kernel. This comprises the controller library and function library.
> > Controller library implements functions specific to an slave controller
> > and function library implements functions specific to an slave function.
> > 
> > Introduce a new configfs entry to configure the slave function configuring
> > and bind the slave function with slave controller.
> > 
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
> >  drivers/i3c/Kconfig       |  26 ++
> >  drivers/i3c/Makefile      |   2 +
> >  drivers/i3c/i3c-cfs.c     | 389 +++++++++++++++++++++++++++++
> >  drivers/i3c/slave.c       | 453 ++++++++++++++++++++++++++++++++++
> >  include/linux/i3c/slave.h | 503 ++++++++++++++++++++++++++++++++++++++
> >  5 files changed, 1373 insertions(+)
> >  create mode 100644 drivers/i3c/i3c-cfs.c
> >  create mode 100644 drivers/i3c/slave.c
> >  create mode 100644 include/linux/i3c/slave.h
> > 
> > diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig
> > index 30a441506f61c..d5f5ca7cd6a56 100644
> > --- a/drivers/i3c/Kconfig
> > +++ b/drivers/i3c/Kconfig
> > @@ -22,3 +22,29 @@ menuconfig I3C
> >  if I3C
> >  source "drivers/i3c/master/Kconfig"
> >  endif # I3C
> > +
> > +config I3C_SLAVE
> 
> It doesn't look like you follow Kernel naming convention (see coding style).

I checked I3C spec. It use words 'target'.
Is it okay using I3C_TARGET?

> 
> > +	bool "I3C Slave Support"
> > +	help
> > +	  Support I3C Slave Mode.
> > +
> 
> 
> 
> Best regards,
> Krzysztof
> 

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

* Re: [PATCH 1/5] i3c: add slave mode support
  2023-10-19 15:02     ` Frank Li
@ 2023-10-19 15:46       ` Greg KH
  2023-10-19 17:06         ` Greg KH
  0 siblings, 1 reply; 17+ messages in thread
From: Greg KH @ 2023-10-19 15:46 UTC (permalink / raw)
  To: Frank Li
  Cc: Krzysztof Kozlowski, miquel.raynal, conor.culhane,
	alexandre.belloni, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	corbet, joe, linux-i3c, devicetree, linux-kernel, linux-doc, imx,
	jirislaby, linux-serial

On Thu, Oct 19, 2023 at 11:02:10AM -0400, Frank Li wrote:
> On Thu, Oct 19, 2023 at 09:00:05AM +0200, Krzysztof Kozlowski wrote:
> > On 18/10/2023 23:58, Frank Li wrote:
> > > Introduce a new slave core layer in order to support slave functions in
> > > linux kernel. This comprises the controller library and function library.
> > > Controller library implements functions specific to an slave controller
> > > and function library implements functions specific to an slave function.
> > > 
> > > Introduce a new configfs entry to configure the slave function configuring
> > > and bind the slave function with slave controller.
> > > 
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> > >  drivers/i3c/Kconfig       |  26 ++
> > >  drivers/i3c/Makefile      |   2 +
> > >  drivers/i3c/i3c-cfs.c     | 389 +++++++++++++++++++++++++++++
> > >  drivers/i3c/slave.c       | 453 ++++++++++++++++++++++++++++++++++
> > >  include/linux/i3c/slave.h | 503 ++++++++++++++++++++++++++++++++++++++
> > >  5 files changed, 1373 insertions(+)
> > >  create mode 100644 drivers/i3c/i3c-cfs.c
> > >  create mode 100644 drivers/i3c/slave.c
> > >  create mode 100644 include/linux/i3c/slave.h
> > > 
> > > diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig
> > > index 30a441506f61c..d5f5ca7cd6a56 100644
> > > --- a/drivers/i3c/Kconfig
> > > +++ b/drivers/i3c/Kconfig
> > > @@ -22,3 +22,29 @@ menuconfig I3C
> > >  if I3C
> > >  source "drivers/i3c/master/Kconfig"
> > >  endif # I3C
> > > +
> > > +config I3C_SLAVE
> > 
> > It doesn't look like you follow Kernel naming convention (see coding style).
> 
> I checked I3C spec. It use words 'target'.
> Is it okay using I3C_TARGET?

Why wouldn't it be?

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

* Re: [PATCH 1/5] i3c: add slave mode support
  2023-10-19 15:46       ` Greg KH
@ 2023-10-19 17:06         ` Greg KH
  0 siblings, 0 replies; 17+ messages in thread
From: Greg KH @ 2023-10-19 17:06 UTC (permalink / raw)
  To: Frank Li
  Cc: Krzysztof Kozlowski, miquel.raynal, conor.culhane,
	alexandre.belloni, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	corbet, joe, linux-i3c, devicetree, linux-kernel, linux-doc, imx,
	jirislaby, linux-serial

On Thu, Oct 19, 2023 at 05:46:42PM +0200, Greg KH wrote:
> On Thu, Oct 19, 2023 at 11:02:10AM -0400, Frank Li wrote:
> > On Thu, Oct 19, 2023 at 09:00:05AM +0200, Krzysztof Kozlowski wrote:
> > > On 18/10/2023 23:58, Frank Li wrote:
> > > > Introduce a new slave core layer in order to support slave functions in
> > > > linux kernel. This comprises the controller library and function library.
> > > > Controller library implements functions specific to an slave controller
> > > > and function library implements functions specific to an slave function.
> > > > 
> > > > Introduce a new configfs entry to configure the slave function configuring
> > > > and bind the slave function with slave controller.
> > > > 
> > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > ---
> > > >  drivers/i3c/Kconfig       |  26 ++
> > > >  drivers/i3c/Makefile      |   2 +
> > > >  drivers/i3c/i3c-cfs.c     | 389 +++++++++++++++++++++++++++++
> > > >  drivers/i3c/slave.c       | 453 ++++++++++++++++++++++++++++++++++
> > > >  include/linux/i3c/slave.h | 503 ++++++++++++++++++++++++++++++++++++++
> > > >  5 files changed, 1373 insertions(+)
> > > >  create mode 100644 drivers/i3c/i3c-cfs.c
> > > >  create mode 100644 drivers/i3c/slave.c
> > > >  create mode 100644 include/linux/i3c/slave.h
> > > > 
> > > > diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig
> > > > index 30a441506f61c..d5f5ca7cd6a56 100644
> > > > --- a/drivers/i3c/Kconfig
> > > > +++ b/drivers/i3c/Kconfig
> > > > @@ -22,3 +22,29 @@ menuconfig I3C
> > > >  if I3C
> > > >  source "drivers/i3c/master/Kconfig"
> > > >  endif # I3C
> > > > +
> > > > +config I3C_SLAVE
> > > 
> > > It doesn't look like you follow Kernel naming convention (see coding style).
> > 
> > I checked I3C spec. It use words 'target'.
> > Is it okay using I3C_TARGET?
> 
> Why wouldn't it be?

Sorry, that was snotty of me, long day of driving, my apologies.  Yes,
please use "target" and the other terminology to reflect this, and not
the ones you used in your driver as it is against the current kernel
coding style rules.

thanks,

greg k-h

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

* Re: [PATCH 1/5] i3c: add slave mode support
  2023-10-18 21:58 ` [PATCH 1/5] i3c: add " Frank Li
  2023-10-19  7:00   ` Krzysztof Kozlowski
@ 2023-10-23  1:11   ` kernel test robot
  2023-10-23  1:20   ` kernel test robot
  2 siblings, 0 replies; 17+ messages in thread
From: kernel test robot @ 2023-10-23  1:11 UTC (permalink / raw)
  To: Frank Li, miquel.raynal, conor.culhane, alexandre.belloni,
	robh+dt, krzysztof.kozlowski+dt, conor+dt, corbet, joe,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: oe-kbuild-all, gregkh, imx, jirislaby, linux-serial

Hi Frank,

kernel test robot noticed the following build warnings:

[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v6.6-rc6 next-20231020]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Frank-Li/i3c-add-slave-mode-support/20231019-055940
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20231018215809.3477437-2-Frank.Li%40nxp.com
patch subject: [PATCH 1/5] i3c: add slave mode support
config: sparc-allyesconfig (https://download.01.org/0day-ci/archive/20231020/202310201829.Hgq2x9nm-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231020/202310201829.Hgq2x9nm-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <yujie.liu@intel.com>
| Closes: https://lore.kernel.org/r/202310201829.Hgq2x9nm-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/i3c/slave.c:166: warning: Function parameter or member 'ctrl' not described in 'devm_i3c_slave_ctrl_destroy'
>> drivers/i3c/slave.c:166: warning: Excess function parameter 'ops' description in 'devm_i3c_slave_ctrl_destroy'
>> drivers/i3c/slave.c:166: warning: Excess function parameter 'owner' description in 'devm_i3c_slave_ctrl_destroy'
>> drivers/i3c/slave.c:228: warning: expecting prototype for i3c_slave_ctrl(). Prototype was for i3c_slave_ctrl_get() instead
>> drivers/i3c/slave.c:420: warning: Function parameter or member 'fd' not described in 'i3c_slave_func_unregister_driver'
>> drivers/i3c/slave.c:420: warning: Excess function parameter 'driver' description in 'i3c_slave_func_unregister_driver'


vim +166 drivers/i3c/slave.c

a63b2858bd837d Frank Li 2023-10-18  154  
a63b2858bd837d Frank Li 2023-10-18  155  /**
a63b2858bd837d Frank Li 2023-10-18  156   * devm_i3c_slave_ctrl_destroy() - destroy the slave controller device
a63b2858bd837d Frank Li 2023-10-18  157   * @dev: device that is creating the new slave controller device
a63b2858bd837d Frank Li 2023-10-18  158   * @ops: function pointers for performing slave controller operations
a63b2858bd837d Frank Li 2023-10-18  159   * @owner: the owner of the module that creates the slave controller device
a63b2858bd837d Frank Li 2023-10-18  160   *
a63b2858bd837d Frank Li 2023-10-18  161   * Invoke to create a new slave controller device and add it to i3c_slave class. While at that, it
a63b2858bd837d Frank Li 2023-10-18  162   * also associates the device with the i3c_slave using devres. On driver detach, release function is
a63b2858bd837d Frank Li 2023-10-18  163   * invoked on the devres data, then devres data is freed.
a63b2858bd837d Frank Li 2023-10-18  164   */
a63b2858bd837d Frank Li 2023-10-18  165  void devm_i3c_slave_ctrl_destroy(struct device *dev, struct i3c_slave_ctrl *ctrl)
a63b2858bd837d Frank Li 2023-10-18 @166  {
a63b2858bd837d Frank Li 2023-10-18  167  	int r;
a63b2858bd837d Frank Li 2023-10-18  168  
a63b2858bd837d Frank Li 2023-10-18  169  	r = devres_destroy(dev, devm_i3c_slave_ctrl_release, devm_i3c_slave_ctrl_match,
a63b2858bd837d Frank Li 2023-10-18  170  			   ctrl);
a63b2858bd837d Frank Li 2023-10-18  171  	dev_WARN_ONCE(dev, r, "couldn't find I3C controller resource\n");
a63b2858bd837d Frank Li 2023-10-18  172  }
a63b2858bd837d Frank Li 2023-10-18  173  EXPORT_SYMBOL_GPL(devm_i3c_slave_ctrl_destroy);
a63b2858bd837d Frank Li 2023-10-18  174  
a63b2858bd837d Frank Li 2023-10-18  175  /**
a63b2858bd837d Frank Li 2023-10-18  176   * i3c_slave_ctrl_destroy() - destroy the slave controller device
a63b2858bd837d Frank Li 2023-10-18  177   * @ctrl: the slave controller device that has to be destroyed
a63b2858bd837d Frank Li 2023-10-18  178   *
a63b2858bd837d Frank Li 2023-10-18  179   * Invoke to destroy the I3C slave device
a63b2858bd837d Frank Li 2023-10-18  180   */
a63b2858bd837d Frank Li 2023-10-18  181  void i3c_slave_ctrl_destroy(struct i3c_slave_ctrl *ctrl)
a63b2858bd837d Frank Li 2023-10-18  182  {
a63b2858bd837d Frank Li 2023-10-18  183  	i3c_slave_cfs_remove_ctrl_group(ctrl->group);
a63b2858bd837d Frank Li 2023-10-18  184  	device_unregister(&ctrl->dev);
a63b2858bd837d Frank Li 2023-10-18  185  }
a63b2858bd837d Frank Li 2023-10-18  186  EXPORT_SYMBOL_GPL(i3c_slave_ctrl_destroy);
a63b2858bd837d Frank Li 2023-10-18  187  
a63b2858bd837d Frank Li 2023-10-18  188  /**
a63b2858bd837d Frank Li 2023-10-18  189   * i3c_slave_ctrl_add_func() - bind I3C slave function to an slave controller
a63b2858bd837d Frank Li 2023-10-18  190   * @ctrl: the controller device to which the slave function should be added
a63b2858bd837d Frank Li 2023-10-18  191   * @func: the slave function to be added
a63b2858bd837d Frank Li 2023-10-18  192   *
a63b2858bd837d Frank Li 2023-10-18  193   * An I3C slave device can have only one functions.
a63b2858bd837d Frank Li 2023-10-18  194   */
a63b2858bd837d Frank Li 2023-10-18  195  int i3c_slave_ctrl_add_func(struct i3c_slave_ctrl *ctrl, struct i3c_slave_func *func)
a63b2858bd837d Frank Li 2023-10-18  196  {
a63b2858bd837d Frank Li 2023-10-18  197  	if (ctrl->func)
a63b2858bd837d Frank Li 2023-10-18  198  		return -EBUSY;
a63b2858bd837d Frank Li 2023-10-18  199  
a63b2858bd837d Frank Li 2023-10-18  200  	ctrl->func = func;
a63b2858bd837d Frank Li 2023-10-18  201  	func->ctrl = ctrl;
a63b2858bd837d Frank Li 2023-10-18  202  
a63b2858bd837d Frank Li 2023-10-18  203  	return 0;
a63b2858bd837d Frank Li 2023-10-18  204  }
a63b2858bd837d Frank Li 2023-10-18  205  EXPORT_SYMBOL_GPL(i3c_slave_ctrl_add_func);
a63b2858bd837d Frank Li 2023-10-18  206  
a63b2858bd837d Frank Li 2023-10-18  207  /**
a63b2858bd837d Frank Li 2023-10-18  208   * i3c_slave_ctrl_remove_func() - unbind I3C slave function to an slave controller
a63b2858bd837d Frank Li 2023-10-18  209   * @ctrl: the controller device to which the slave function should be removed
a63b2858bd837d Frank Li 2023-10-18  210   * @func: the slave function to be removed
a63b2858bd837d Frank Li 2023-10-18  211   *
a63b2858bd837d Frank Li 2023-10-18  212   * An I3C slave device can have only one functions.
a63b2858bd837d Frank Li 2023-10-18  213   */
a63b2858bd837d Frank Li 2023-10-18  214  void i3c_slave_ctrl_remove_func(struct i3c_slave_ctrl *ctrl, struct i3c_slave_func *func)
a63b2858bd837d Frank Li 2023-10-18  215  {
a63b2858bd837d Frank Li 2023-10-18  216  	ctrl->func = NULL;
a63b2858bd837d Frank Li 2023-10-18  217  }
a63b2858bd837d Frank Li 2023-10-18  218  EXPORT_SYMBOL_GPL(i3c_slave_ctrl_remove_func);
a63b2858bd837d Frank Li 2023-10-18  219  
a63b2858bd837d Frank Li 2023-10-18  220  /**
a63b2858bd837d Frank Li 2023-10-18  221   * i3c_slave_ctrl() - get the I3C slave controller
a63b2858bd837d Frank Li 2023-10-18  222   * @name: device name of the slave controller
a63b2858bd837d Frank Li 2023-10-18  223   *
a63b2858bd837d Frank Li 2023-10-18  224   * Invoke to get struct i3c_slave_ctrl * corresponding to the device name of the
a63b2858bd837d Frank Li 2023-10-18  225   * slave controller
a63b2858bd837d Frank Li 2023-10-18  226   */
a63b2858bd837d Frank Li 2023-10-18  227  struct i3c_slave_ctrl *i3c_slave_ctrl_get(const char *name)
a63b2858bd837d Frank Li 2023-10-18 @228  {
a63b2858bd837d Frank Li 2023-10-18  229  	int ret = -EINVAL;
a63b2858bd837d Frank Li 2023-10-18  230  	struct i3c_slave_ctrl *ctrl;
a63b2858bd837d Frank Li 2023-10-18  231  	struct device *dev;
a63b2858bd837d Frank Li 2023-10-18  232  	struct class_dev_iter iter;
a63b2858bd837d Frank Li 2023-10-18  233  
a63b2858bd837d Frank Li 2023-10-18  234  	class_dev_iter_init(&iter, i3c_slave_ctrl_class, NULL, NULL);
a63b2858bd837d Frank Li 2023-10-18  235  	while ((dev = class_dev_iter_next(&iter))) {
a63b2858bd837d Frank Li 2023-10-18  236  		if (strcmp(name, dev_name(dev)))
a63b2858bd837d Frank Li 2023-10-18  237  			continue;
a63b2858bd837d Frank Li 2023-10-18  238  
a63b2858bd837d Frank Li 2023-10-18  239  		ctrl = to_i3c_slave_ctrl(dev);
a63b2858bd837d Frank Li 2023-10-18  240  		if (!try_module_get(ctrl->ops->owner)) {
a63b2858bd837d Frank Li 2023-10-18  241  			ret = -EINVAL;
a63b2858bd837d Frank Li 2023-10-18  242  			goto err;
a63b2858bd837d Frank Li 2023-10-18  243  		}
a63b2858bd837d Frank Li 2023-10-18  244  
a63b2858bd837d Frank Li 2023-10-18  245  		class_dev_iter_exit(&iter);
a63b2858bd837d Frank Li 2023-10-18  246  		get_device(&ctrl->dev);
a63b2858bd837d Frank Li 2023-10-18  247  		return ctrl;
a63b2858bd837d Frank Li 2023-10-18  248  	}
a63b2858bd837d Frank Li 2023-10-18  249  
a63b2858bd837d Frank Li 2023-10-18  250  err:
a63b2858bd837d Frank Li 2023-10-18  251  	class_dev_iter_exit(&iter);
a63b2858bd837d Frank Li 2023-10-18  252  	return ERR_PTR(ret);
a63b2858bd837d Frank Li 2023-10-18  253  }
a63b2858bd837d Frank Li 2023-10-18  254  EXPORT_SYMBOL_GPL(i3c_slave_ctrl_get);
a63b2858bd837d Frank Li 2023-10-18  255  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


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

* Re: [PATCH 1/5] i3c: add slave mode support
  2023-10-18 21:58 ` [PATCH 1/5] i3c: add " Frank Li
  2023-10-19  7:00   ` Krzysztof Kozlowski
  2023-10-23  1:11   ` kernel test robot
@ 2023-10-23  1:20   ` kernel test robot
  2 siblings, 0 replies; 17+ messages in thread
From: kernel test robot @ 2023-10-23  1:20 UTC (permalink / raw)
  To: Frank Li, miquel.raynal, conor.culhane, alexandre.belloni,
	robh+dt, krzysztof.kozlowski+dt, conor+dt, corbet, joe,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: oe-kbuild-all, gregkh, imx, jirislaby, linux-serial

Hi Frank,

kernel test robot noticed the following build warnings:

[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v6.6-rc6 next-20231020]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Frank-Li/i3c-add-slave-mode-support/20231019-055940
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20231018215809.3477437-2-Frank.Li%40nxp.com
patch subject: [PATCH 1/5] i3c: add slave mode support
config: microblaze-allyesconfig (https://download.01.org/0day-ci/archive/20231021/202310211527.TeVTMxA7-lkp@intel.com/config)
compiler: microblaze-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231021/202310211527.TeVTMxA7-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <yujie.liu@intel.com>
| Closes: https://lore.kernel.org/r/202310211527.TeVTMxA7-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/i3c/slave.c:11:
   include/linux/i3c/slave.h: In function 'i3c_slave_ctrl_alloc_request':
   include/linux/i3c/slave.h:272:23: error: implicit declaration of function 'kzalloc' [-Werror=implicit-function-declaration]
     272 |                 req = kzalloc(sizeof(*req), gfp_flags);
         |                       ^~~~~~~
>> include/linux/i3c/slave.h:272:21: warning: assignment to 'struct i3c_request *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     272 |                 req = kzalloc(sizeof(*req), gfp_flags);
         |                     ^
   include/linux/i3c/slave.h: In function 'i3c_slave_ctrl_free_request':
   include/linux/i3c/slave.h:298:17: error: implicit declaration of function 'kfree'; did you mean 'kvfree'? [-Werror=implicit-function-declaration]
     298 |                 kfree(req);
         |                 ^~~~~
         |                 kvfree
   In file included from drivers/i3c/slave.c:13:
   include/linux/slab.h: At top level:
>> include/linux/slab.h:227:6: warning: conflicting types for 'kfree'; have 'void(const void *)'
     227 | void kfree(const void *objp);
         |      ^~~~~
   include/linux/i3c/slave.h:298:17: note: previous implicit declaration of 'kfree' with type 'void(const void *)'
     298 |                 kfree(req);
         |                 ^~~~~
   include/linux/slab.h:718:37: error: conflicting types for 'kzalloc'; have 'void *(size_t,  gfp_t)' {aka 'void *(unsigned int,  unsigned int)'}
     718 | static inline __alloc_size(1) void *kzalloc(size_t size, gfp_t flags)
         |                                     ^~~~~~~
   include/linux/i3c/slave.h:272:23: note: previous implicit declaration of 'kzalloc' with type 'int()'
     272 |                 req = kzalloc(sizeof(*req), gfp_flags);
         |                       ^~~~~~~
   cc1: some warnings being treated as errors


vim +272 include/linux/i3c/slave.h

a63b2858bd837d Frank Li 2023-10-18  256  
a63b2858bd837d Frank Li 2023-10-18  257  /**
a63b2858bd837d Frank Li 2023-10-18  258   * i3c_slave_ctrl_alloc_request() - Alloc an I3C transfer
a63b2858bd837d Frank Li 2023-10-18  259   * @ctrl: I3C slave controller device
a63b2858bd837d Frank Li 2023-10-18  260   * gfp_flags: additional gfp flags used when allocating the buffers
a63b2858bd837d Frank Li 2023-10-18  261   *
a63b2858bd837d Frank Li 2023-10-18  262   * Returns: Zero for success, or an error code in case of failure
a63b2858bd837d Frank Li 2023-10-18  263   */
a63b2858bd837d Frank Li 2023-10-18  264  static inline struct i3c_request *
a63b2858bd837d Frank Li 2023-10-18  265  i3c_slave_ctrl_alloc_request(struct i3c_slave_ctrl *ctrl, gfp_t gfp_flags)
a63b2858bd837d Frank Li 2023-10-18  266  {
a63b2858bd837d Frank Li 2023-10-18  267  	struct i3c_request *req = NULL;
a63b2858bd837d Frank Li 2023-10-18  268  
a63b2858bd837d Frank Li 2023-10-18  269  	if (ctrl && ctrl->ops && ctrl->ops->alloc_request)
a63b2858bd837d Frank Li 2023-10-18  270  		req = ctrl->ops->alloc_request(ctrl, gfp_flags);
a63b2858bd837d Frank Li 2023-10-18  271  	else
a63b2858bd837d Frank Li 2023-10-18 @272  		req = kzalloc(sizeof(*req), gfp_flags);
a63b2858bd837d Frank Li 2023-10-18  273  
a63b2858bd837d Frank Li 2023-10-18  274  	if (req)
a63b2858bd837d Frank Li 2023-10-18  275  		req->ctrl = ctrl;
a63b2858bd837d Frank Li 2023-10-18  276  
a63b2858bd837d Frank Li 2023-10-18  277  	return req;
a63b2858bd837d Frank Li 2023-10-18  278  }
a63b2858bd837d Frank Li 2023-10-18  279  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


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

* Re: [PATCH 3/5] i3c: slave: add svc slave controller support
  2023-10-18 21:58 ` [PATCH 3/5] i3c: slave: add svc slave controller support Frank Li
@ 2023-10-23  1:29   ` kernel test robot
  0 siblings, 0 replies; 17+ messages in thread
From: kernel test robot @ 2023-10-23  1:29 UTC (permalink / raw)
  To: Frank Li, miquel.raynal, conor.culhane, alexandre.belloni,
	robh+dt, krzysztof.kozlowski+dt, conor+dt, corbet, joe,
	linux-i3c, devicetree, linux-kernel, linux-doc
  Cc: oe-kbuild-all, gregkh, imx, jirislaby, linux-serial

Hi Frank,

kernel test robot noticed the following build warnings:

[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v6.6-rc6 next-20231020]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Frank-Li/i3c-add-slave-mode-support/20231019-055940
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20231018215809.3477437-4-Frank.Li%40nxp.com
patch subject: [PATCH 3/5] i3c: slave: add svc slave controller support
config: sparc-allyesconfig (https://download.01.org/0day-ci/archive/20231020/202310201945.nRKjcul0-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231020/202310201945.nRKjcul0-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <yujie.liu@intel.com>
| Closes: https://lore.kernel.org/r/202310201945.nRKjcul0-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/i3c/slave/svc-i3c-slave.c:211:39: warning: no previous prototype for 'svc_i3c_get_features' [-Wmissing-prototypes]
     211 | const struct i3c_slave_ctrl_features *svc_i3c_get_features(struct i3c_slave_ctrl *ctrl)
         |                                       ^~~~~~~~~~~~~~~~~~~~
>> drivers/i3c/slave/svc-i3c-slave.c:666:5: warning: no previous prototype for 'svc_i3c_fifo_status' [-Wmissing-prototypes]
     666 | int svc_i3c_fifo_status(struct i3c_slave_ctrl *ctrl, bool tx)
         |     ^~~~~~~~~~~~~~~~~~~


vim +/svc_i3c_get_features +211 drivers/i3c/slave/svc-i3c-slave.c

10d1fc84a07d32 Frank Li 2023-10-18  210  
10d1fc84a07d32 Frank Li 2023-10-18 @211  const struct i3c_slave_ctrl_features *svc_i3c_get_features(struct i3c_slave_ctrl *ctrl)
10d1fc84a07d32 Frank Li 2023-10-18  212  {
10d1fc84a07d32 Frank Li 2023-10-18  213  	struct svc_i3c_slave *svc;
10d1fc84a07d32 Frank Li 2023-10-18  214  
10d1fc84a07d32 Frank Li 2023-10-18  215  	svc = dev_get_drvdata(&ctrl->dev);
10d1fc84a07d32 Frank Li 2023-10-18  216  
10d1fc84a07d32 Frank Li 2023-10-18  217  	if (!svc)
10d1fc84a07d32 Frank Li 2023-10-18  218  		return NULL;
10d1fc84a07d32 Frank Li 2023-10-18  219  
10d1fc84a07d32 Frank Li 2023-10-18  220  	return &svc->features;
10d1fc84a07d32 Frank Li 2023-10-18  221  }
10d1fc84a07d32 Frank Li 2023-10-18  222  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


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

end of thread, other threads:[~2023-10-23  1:34 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-18 21:58 [PATCH 0/5] I3C slave mode support Frank Li
2023-10-18 21:58 ` [PATCH 1/5] i3c: add " Frank Li
2023-10-19  7:00   ` Krzysztof Kozlowski
2023-10-19 15:02     ` Frank Li
2023-10-19 15:46       ` Greg KH
2023-10-19 17:06         ` Greg KH
2023-10-23  1:11   ` kernel test robot
2023-10-23  1:20   ` kernel test robot
2023-10-18 21:58 ` [PATCH 2/5] dt-bindings: i3c: svc: add compatible string i3c: silvaco,i3c-slave Frank Li
2023-10-19  7:00   ` Krzysztof Kozlowski
2023-10-19 12:07   ` Rob Herring
2023-10-18 21:58 ` [PATCH 3/5] i3c: slave: add svc slave controller support Frank Li
2023-10-23  1:29   ` kernel test robot
2023-10-18 21:58 ` [PATCH 4/5] i3c: slave: func: add tty driver Frank Li
2023-10-19  7:21   ` Jiri Slaby
2023-10-18 21:58 ` [PATCH 5/5] Documentation: i3c: Add I3C slave mode controller and function Frank Li
2023-10-18 22:07   ` Frank Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).