All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/3] Create common DPLL/clock configuration API
@ 2022-06-22  0:06 Vadim Fedorenko
  2022-06-22  0:06 ` [RFC PATCH 1/3] dpll: Add DPLL framework base functions Vadim Fedorenko
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Vadim Fedorenko @ 2022-06-22  0:06 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Vadim Fedorenko, Aya Levin, Arkadiusz Kubalewski, netdev,
	linux-arm-kernel

From: Vadim Fedorenko <vadfed@fb.com>

Implement common API for clock/DPLL configuration and status reporting.
The API utilises netlink interface as transport for commands and event
notifications. This API aim to extend current pin configuration and 
make it flexible and easy to cover special configurations.

Vadim Fedorenko (3):
  dpll: Add DPLL framework base functions
  dpll: add netlink events
  ptp_ocp: implement DPLL ops

 MAINTAINERS                 |   8 +
 drivers/Kconfig             |   2 +
 drivers/Makefile            |   1 +
 drivers/dpll/Kconfig        |   7 +
 drivers/dpll/Makefile       |   7 +
 drivers/dpll/dpll_core.c    | 146 +++++++++
 drivers/dpll/dpll_core.h    |  40 +++
 drivers/dpll/dpll_netlink.c | 583 ++++++++++++++++++++++++++++++++++++
 drivers/dpll/dpll_netlink.h |  14 +
 drivers/ptp/Kconfig         |   1 +
 drivers/ptp/ptp_ocp.c       |  85 ++++++
 include/linux/dpll.h        |  24 ++
 include/uapi/linux/dpll.h   |  77 +++++
 13 files changed, 995 insertions(+)
 create mode 100644 drivers/dpll/Kconfig
 create mode 100644 drivers/dpll/Makefile
 create mode 100644 drivers/dpll/dpll_core.c
 create mode 100644 drivers/dpll/dpll_core.h
 create mode 100644 drivers/dpll/dpll_netlink.c
 create mode 100644 drivers/dpll/dpll_netlink.h
 create mode 100644 include/linux/dpll.h
 create mode 100644 include/uapi/linux/dpll.h

-- 
2.27.0


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

* [RFC PATCH 1/3] dpll: Add DPLL framework base functions
  2022-06-22  0:06 [RFC PATCH 0/3] Create common DPLL/clock configuration API Vadim Fedorenko
@ 2022-06-22  0:06 ` Vadim Fedorenko
  2022-06-22  0:06 ` [RFC PATCH 2/3] dpll: add netlink events Vadim Fedorenko
  2022-06-22  0:06 ` [RFC PATCH 3/3] ptp_ocp: implement DPLL ops Vadim Fedorenko
  2 siblings, 0 replies; 6+ messages in thread
From: Vadim Fedorenko @ 2022-06-22  0:06 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Vadim Fedorenko, Aya Levin, Arkadiusz Kubalewski, netdev,
	linux-arm-kernel

From: Vadim Fedorenko <vadfed@fb.com>

DPLL framework is used to represent and configure DPLL devices
in systems. Each device that has DPLL and can configure sources
and outputs can use this framework.

Signed-off-by: Vadim Fedorenko <vadfed@fb.com>
---
 MAINTAINERS                 |   8 +
 drivers/Kconfig             |   2 +
 drivers/Makefile            |   1 +
 drivers/dpll/Kconfig        |   7 +
 drivers/dpll/Makefile       |   7 +
 drivers/dpll/dpll_core.c    | 144 ++++++++++++
 drivers/dpll/dpll_core.h    |  40 ++++
 drivers/dpll/dpll_netlink.c | 436 ++++++++++++++++++++++++++++++++++++
 drivers/dpll/dpll_netlink.h |   7 +
 include/linux/dpll.h        |  24 ++
 include/uapi/linux/dpll.h   |  77 +++++++
 11 files changed, 753 insertions(+)
 create mode 100644 drivers/dpll/Kconfig
 create mode 100644 drivers/dpll/Makefile
 create mode 100644 drivers/dpll/dpll_core.c
 create mode 100644 drivers/dpll/dpll_core.h
 create mode 100644 drivers/dpll/dpll_netlink.c
 create mode 100644 drivers/dpll/dpll_netlink.h
 create mode 100644 include/linux/dpll.h
 create mode 100644 include/uapi/linux/dpll.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 05fcbea3e432..ead0d9ca9475 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6122,6 +6122,14 @@ F:	Documentation/networking/device_drivers/ethernet/freescale/dpaa2/switch-drive
 F:	drivers/net/ethernet/freescale/dpaa2/dpaa2-switch*
 F:	drivers/net/ethernet/freescale/dpaa2/dpsw*
 
+DPLL CLOCK SUBSYSTEM
+M:	Vadim Fedorenko <vadfed@fb.com>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	drivers/dpll/*
+F:	include/net/dpll.h
+F:	include/uapi/linux/dpll.h
+
 DPT_I2O SCSI RAID DRIVER
 M:	Adaptec OEM Raid Solutions <aacraid@microsemi.com>
 L:	linux-scsi@vger.kernel.org
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b6a172d32a7d..dcdc23116eb8 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -241,4 +241,6 @@ source "drivers/peci/Kconfig"
 
 source "drivers/hte/Kconfig"
 
+source "drivers/dpll/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 9a30842b22c5..acc370a2cda6 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -189,3 +189,4 @@ obj-$(CONFIG_COUNTER)		+= counter/
 obj-$(CONFIG_MOST)		+= most/
 obj-$(CONFIG_PECI)		+= peci/
 obj-$(CONFIG_HTE)		+= hte/
+obj-$(CONFIG_DPLL)		+= dpll/
diff --git a/drivers/dpll/Kconfig b/drivers/dpll/Kconfig
new file mode 100644
index 000000000000..a4cae73f20d3
--- /dev/null
+++ b/drivers/dpll/Kconfig
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Generic DPLL drivers configuration
+#
+
+config DPLL
+  bool
diff --git a/drivers/dpll/Makefile b/drivers/dpll/Makefile
new file mode 100644
index 000000000000..0748c80097e4
--- /dev/null
+++ b/drivers/dpll/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for DPLL drivers.
+#
+
+obj-$(CONFIG_DPLL)          += dpll_sys.o
+dpll_sys-y                  += dpll_core.o dpll_netlink.o
diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c
new file mode 100644
index 000000000000..a6d6ea828073
--- /dev/null
+++ b/drivers/dpll/dpll_core.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  dpll_core.c - Generic DPLL Management class support.
+ *
+ *  Copyright (c) 2021 Meta Platforms, Inc. and affiliates
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "dpll_core.h"
+
+static DEFINE_MUTEX(dpll_device_xa_lock);
+static DEFINE_XARRAY_ALLOC(dpll_device_xa);
+static DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC);
+#define DPLL_REGISTERED XA_MARK_1
+
+#define ASSERT_DPLL_REGISTERED(d)                                           \
+	WARN_ON_ONCE(!xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED))
+#define ASSERT_DPLL_NOT_REGISTERED(d)                                      \
+	WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED))
+
+
+int for_each_dpll_device(int id, int (*cb)(struct dpll_device *, void *), void *data)
+{
+	struct dpll_device *dpll;
+	unsigned long index;
+	int ret = 0;
+
+	mutex_lock(&dpll_device_xa_lock);
+	xa_for_each_start(&dpll_device_xa, index, dpll, id) {
+		if (!xa_get_mark(&dpll_device_xa, index, DPLL_REGISTERED)
+			continue;
+		ret = cb(dpll, data);
+		if (ret)
+			break;
+	}
+	mutex_unlock(&dpll_device_xa_lock);
+
+	return ret;
+}
+
+struct dpll_device *dpll_device_get_by_id(int id)
+{
+	struct dpll_device *dpll = NULL;
+
+	if (xa_get_mark(&dpll_device_xa, id, DPLL_REGISTERED))
+		dpll = xa_load(&dpll_device_xa, id);
+	return dpll;
+}
+
+static void dpll_device_release(struct device *dev)
+{
+	struct dpll_device *dpll;
+
+	dpll = to_dpll_device(dev);
+
+	dpll_device_unregister(dpll);
+
+	mutex_destroy(&dpll->lock);
+	kfree(dpll);
+}
+
+static struct class dpll_class = {
+	.name = "dpll",
+	.dev_release = dpll_device_release,
+};
+
+struct dpll_device *dpll_device_alloc(struct dpll_device_ops *ops, int sources_count,
+					 int outputs_count, void *priv)
+{
+	struct dpll_device *dpll;
+	int ret;
+
+	dpll = kzalloc(sizeof(*dpll), GFP_KERNEL);
+	if (!dpll)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_init(&dpll->lock);
+	dpll->ops = ops;
+	dpll->dev.class = &dpll_class;
+	dpll->sources_count = sources_count;
+	dpll->outputs_count = outputs_count;
+
+	mutex_lock(&dpll_device_xa_lock);
+	ret = xa_alloc(&dpll_device_xa, &dpll->id, dpll, xa_limit_16b, GFP_KERNEL);
+	if (ret)
+		goto error;
+	dev_set_name(&dpll->dev, "dpll%d", dpll->id);
+	mutex_unlock(&dpll_device_xa_lock);
+	dpll->priv = priv;
+
+	return dpll;
+
+error:
+	mutex_unlock(&dpll_device_xa_lock);
+	kfree(dpll);
+	return ERR_PTR(ret);
+}
+
+void dpll_device_register(struct dpll_device *dpll)
+{
+	ASSERT_DPLL_NOT_REGISTERED(dpll);
+
+	mutex_lock(&dpll_device_xa_lock);
+	xa_set_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED);
+	dpll_notify_device_create(dpll->id, dev_name(&dpll->dev));
+	mutex_unlock(&dpll_device_xa_lock);
+}
+
+void dpll_device_unregister(struct dpll_device *dpll)
+{
+	ASSERT_DPLL_REGISTERED(dpll);
+
+	mutex_lock(&dpll_device_xa_lock);
+	xa_erase(&dpll_device_xa, dpll->id);
+	mutex_unlock(&dpll_device_xa_lock);
+}
+
+static int __init dpll_init(void)
+{
+	int ret;
+
+	ret = dpll_netlink_init();
+	if (ret)
+		goto error;
+
+	ret = class_register(&dpll_class);
+	if (ret)
+		goto unregister_netlink;
+
+	return 0;
+
+unregister_netlink:
+	dpll_netlink_finish();
+error:
+	mutex_destroy(&dpll_device_xa_lock);
+	return ret;
+}
+subsys_initcall(dpll_init);
diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h
new file mode 100644
index 000000000000..5ad3224d5caf
--- /dev/null
+++ b/drivers/dpll/dpll_core.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright (c) 2021 Meta Platforms, Inc. and affiliates
+ */
+
+#ifndef __DPLL_CORE_H__
+#define __DPLL_CORE_H__
+
+#include <linux/dpll.h>
+
+#include "dpll_netlink.h"
+
+/**
+ * struct dpll_device - structure for a DPLL device
+ * @id:		unique id number for each edvice
+ * @dev:	&struct device for this dpll device
+ * @sources_count:	amount of input sources this dpll_device supports
+ * @outputs_count:	amount of outputs this dpll_device supports
+ * @ops:	operations this &dpll_device supports
+ * @lock:	mutex to serialize operations
+ * @priv:	pointer to private information of owner
+ */
+struct dpll_device {
+	int id;
+	struct device dev;
+	int sources_count;
+	int outputs_count;
+	struct dpll_device_ops *ops;
+	struct mutex lock;
+	void *priv;
+};
+
+#define to_dpll_device(_dev) \
+	container_of(_dev, struct dpll_device, dev)
+
+int for_each_dpll_device(int id, int (*cb)(struct dpll_device *, void *),
+			  void *data);
+struct dpll_device *dpll_device_get_by_id(int id);
+void dpll_device_unregister(struct dpll_device *dpll);
+#endif
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
new file mode 100644
index 000000000000..85a4b0c8c2f2
--- /dev/null
+++ b/drivers/dpll/dpll_netlink.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generic netlink for DPLL management framework
+ *
+ * Copyright (c) 2021 Meta Platforms, Inc. and affiliates
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <net/genetlink.h>
+#include "dpll_core.h"
+
+#include <uapi/linux/dpll.h>
+
+static const struct genl_multicast_group dpll_genl_mcgrps[] = {
+	{ .name = DPLL_CONFIG_DEVICE_GROUP_NAME, },
+	{ .name = DPLL_CONFIG_SOURCE_GROUP_NAME, },
+	{ .name = DPLL_CONFIG_OUTPUT_GROUP_NAME, },
+	{ .name = DPLL_MONITOR_GROUP_NAME,  },
+};
+
+static const struct nla_policy dpll_genl_get_policy[] = {
+	[DPLLA_DEVICE_ID]	= { .type = NLA_U32 },
+	[DPLLA_DEVICE_NAME]	= { .type = NLA_STRING,
+				    .len = DPLL_NAME_LENGTH },
+	[DPLLA_FLAGS]		= { .type = NLA_U32 },
+};
+
+static const struct nla_policy dpll_genl_set_source_policy[] = {
+	[DPLLA_DEVICE_ID]	= { .type = NLA_U32 },
+	[DPLLA_SOURCE_ID]	= { .type = NLA_U32 },
+	[DPLLA_SOURCE_TYPE]	= { .type = NLA_U32 },
+};
+
+static const struct nla_policy dpll_genl_set_output_policy[] = {
+	[DPLLA_DEVICE_ID]	= { .type = NLA_U32 },
+	[DPLLA_OUTPUT_ID]	= { .type = NLA_U32 },
+	[DPLLA_OUTPUT_TYPE]	= { .type = NLA_U32 },
+};
+
+struct param {
+	struct netlink_callback *cb;
+	struct dpll_device *dpll;
+	struct nlattr **attrs;
+	struct sk_buff *msg;
+	int dpll_id;
+	int dpll_source_id;
+	int dpll_source_type;
+	int dpll_output_id;
+	int dpll_output_type;
+};
+
+struct dpll_dump_ctx {
+	struct dpll_device *dev;
+	int flags;
+	int pos_idx;
+	int pos_src_idx;
+	int pos_out_idx;
+};
+
+typedef int (*cb_t)(struct param *);
+
+static struct genl_family dpll_gnl_family;
+
+static struct dpll_dump_ctx *dpll_dump_context(struct netlink_callback *cb)
+{
+	return (struct dpll_dump_ctx *)cb->ctx;
+}
+
+static int __dpll_cmd_device_dump_one(struct dpll_device *dpll,
+					   struct sk_buff *msg)
+{
+	if (nla_put_u32(msg, DPLLA_DEVICE_ID, dpll->id))
+		return -EMSGSIZE;
+
+	if (nla_put_string(msg, DPLLA_DEVICE_NAME, dev_name(&dpll->dev)))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int __dpll_cmd_dump_sources(struct dpll_device *dpll,
+					   struct sk_buff *msg)
+{
+	struct nlattr *src_attr;
+	int i, ret = 0, type;
+
+	for (i = 0; i < dpll->sources_count; i++) {
+		src_attr = nla_nest_start(msg, DPLLA_SOURCE);
+		if (!src_attr) {
+			ret = -EMSGSIZE;
+			break;
+		}
+		type = dpll->ops->get_source_type(dpll, i);
+		if (nla_put_u32(msg, DPLLA_SOURCE_ID, i) ||
+		    nla_put_u32(msg, DPLLA_SOURCE_TYPE, type)) {
+			nla_nest_cancel(msg, src_attr);
+			ret = -EMSGSIZE;
+			break;
+		}
+		nla_nest_end(msg, src_attr);
+	}
+
+	return ret;
+}
+
+static int __dpll_cmd_dump_outputs(struct dpll_device *dpll,
+					   struct sk_buff *msg)
+{
+	struct nlattr *out_attr;
+	int i, ret = 0, type;
+
+	for (i = 0; i < dpll->outputs_count; i++) {
+		out_attr = nla_nest_start(msg, DPLLA_OUTPUT);
+		if (!out_attr) {
+			ret = -EMSGSIZE;
+			break;
+		}
+		type = dpll->ops->get_source_type(dpll, i);
+		if (nla_put_u32(msg, DPLLA_OUTPUT_ID, i) ||
+		    nla_put_u32(msg, DPLLA_OUTPUT_TYPE, type)) {
+			nla_nest_cancel(msg, out_attr);
+			ret = -EMSGSIZE;
+			break;
+		}
+		nla_nest_end(msg, out_attr);
+	}
+
+	return ret;
+}
+
+static int __dpll_cmd_dump_status(struct dpll_device *dpll,
+					   struct sk_buff *msg)
+{
+	int ret;
+
+	if (!dpll->ops->get_status && !dpll->ops->get_temp && !dpll->ops->get_lock_status)
+		return 0;
+
+	if (dpll->ops->get_status) {
+		ret = dpll->ops->get_status(dpll);
+		if (nla_put_u32(msg, DPLLA_STATUS, ret))
+			return -EMSGSIZE;
+	}
+
+	if (dpll->ops->get_temp) {
+		ret = dpll->ops->get_status(dpll);
+		if (nla_put_u32(msg, DPLLA_TEMP, ret))
+			return -EMSGSIZE;
+	}
+
+	if (dpll->ops->get_lock_status) {
+		ret = dpll->ops->get_lock_status(dpll);
+		if (nla_put_u32(msg, DPLLA_LOCK_STATUS, ret))
+			return -EMSGSIZE;
+	}
+
+	return 0;
+}
+
+static int dpll_device_dump_one(struct dpll_device *dev, struct sk_buff *msg, int flags)
+{
+	struct nlattr *hdr;
+	int ret;
+
+	hdr = nla_nest_start(msg, DPLLA_DEVICE);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	mutex_lock(&dev->lock);
+	ret = __dpll_cmd_device_dump_one(dev, msg);
+	if (ret)
+		goto out_cancel_nest;
+
+	if (flags & DPLL_FLAG_SOURCES && dev->ops->get_source_type) {
+		ret = __dpll_cmd_dump_sources(dev, msg);
+		if (ret)
+			goto out_cancel_nest;
+	}
+
+	if (flags & DPLL_FLAG_OUTPUTS && dev->ops->get_output_type) {
+		ret = __dpll_cmd_dump_outputs(dev, msg);
+		if (ret)
+			goto out_cancel_nest;
+	}
+
+	if (flags & DPLL_FLAG_STATUS) {
+		ret = __dpll_cmd_dump_status(dev, msg);
+		if (ret)
+			goto out_cancel_nest;
+	}
+
+	mutex_unlock(&dev->lock);
+	nla_nest_end(msg, hdr);
+
+	return 0;
+
+out_cancel_nest:
+	mutex_unlock(&dev->lock);
+	nla_nest_cancel(msg, hdr);
+
+	return ret;
+}
+
+static int dpll_genl_cmd_set_source(struct param *p)
+{
+	const struct genl_dumpit_info *info = genl_dumpit_info(p->cb);
+	struct dpll_device *dpll = p->dpll;
+	int ret = 0, src_id, type;
+
+	if (!info->attrs[DPLLA_SOURCE_ID] ||
+	    !info->attrs[DPLLA_SOURCE_TYPE])
+		return -EINVAL;
+
+	if (!dpll->ops->set_source_type)
+		return -EOPNOTSUPP;
+
+	src_id = nla_get_u32(info->attrs[DPLLA_SOURCE_ID]);
+	type = nla_get_u32(info->attrs[DPLLA_SOURCE_TYPE]);
+
+	mutex_lock(&dpll->lock);
+	ret = dpll->ops->set_source_type(dpll, src_id, type);
+	mutex_unlock(&dpll->lock);
+
+	return ret;
+}
+
+static int dpll_genl_cmd_set_output(struct param *p)
+{
+	const struct genl_dumpit_info *info = genl_dumpit_info(p->cb);
+	struct dpll_device *dpll = p->dpll;
+	int ret = 0, out_id, type;
+
+	if (!info->attrs[DPLLA_OUTPUT_ID] ||
+	    !info->attrs[DPLLA_OUTPUT_TYPE])
+		return -EINVAL;
+
+	if (!dpll->ops->set_output_type)
+		return -EOPNOTSUPP;
+
+	out_id = nla_get_u32(info->attrs[DPLLA_OUTPUT_ID]);
+	type = nla_get_u32(info->attrs[DPLLA_OUTPUT_TYPE]);
+
+	mutex_lock(&dpll->lock);
+	ret = dpll->ops->set_source_type(dpll, out_id, type);
+	mutex_unlock(&dpll->lock);
+
+	return ret;
+}
+
+static int dpll_device_loop_cb(struct dpll_device *dpll, void *data)
+{
+	struct dpll_dump_ctx *ctx;
+	struct param *p = (struct param *)data;
+
+	ctx = dpll_dump_context(p->cb);
+
+	ctx->pos_idx = dpll->id;
+
+	return dpll_device_dump_one(dpll, p->msg, ctx->flags);
+}
+
+static int dpll_cmd_device_dump(struct param *p)
+{
+	struct dpll_dump_ctx *ctx = dpll_dump_context(p->cb);
+
+	return for_each_dpll_device(ctx->pos_idx, dpll_device_loop_cb, p);
+}
+
+static int dpll_genl_cmd_device_get_id(struct param *p)
+{
+	struct dpll_device *dpll = p->dpll;
+	int flags = 0;
+
+	if (p->attrs[DPLLA_FLAGS])
+		flags = nla_get_u32(p->attrs[DPLLA_FLAGS]);
+
+	return dpll_device_dump_one(dpll, p->msg, flags);
+}
+
+static cb_t cmd_doit_cb[] = {
+	[DPLL_CMD_DEVICE_GET]		= dpll_genl_cmd_device_get_id,
+	[DPLL_CMD_SET_SOURCE_TYPE]	= dpll_genl_cmd_set_source,
+	[DPLL_CMD_SET_OUTPUT_TYPE]	= dpll_genl_cmd_set_output,
+};
+
+static cb_t cmd_dump_cb[] = {
+	[DPLL_CMD_DEVICE_GET]		= dpll_cmd_device_dump,
+};
+
+static int dpll_genl_cmd_start(struct netlink_callback *cb)
+{
+	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
+	struct dpll_dump_ctx *ctx = dpll_dump_context(cb);
+
+	ctx->dev = NULL;
+	if (info->attrs[DPLLA_FLAGS])
+		ctx->flags = nla_get_u32(info->attrs[DPLLA_FLAGS]);
+	else
+		ctx->flags = 0;
+	ctx->pos_idx = 0;
+	ctx->pos_src_idx = 0;
+	ctx->pos_out_idx = 0;
+	return 0;
+}
+
+static int dpll_genl_cmd_dumpit(struct sk_buff *skb,
+				   struct netlink_callback *cb)
+{
+	struct param p = { .cb = cb, .msg = skb };
+	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
+	int cmd = info->op.cmd;
+	int ret;
+	void *hdr;
+
+	hdr = genlmsg_put(skb, 0, 0, &dpll_gnl_family, 0, cmd);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	ret = cmd_dump_cb[cmd](&p);
+	if (ret)
+		goto out_cancel_msg;
+
+	genlmsg_end(skb, hdr);
+
+	return 0;
+
+out_cancel_msg:
+	genlmsg_cancel(skb, hdr);
+
+	return ret;
+}
+
+static int dpll_genl_cmd_doit(struct sk_buff *skb,
+				 struct genl_info *info)
+{
+	struct param p = { .attrs = info->attrs, .dpll = info->user_ptr[0] };
+	int cmd = info->genlhdr->cmd;
+	struct sk_buff *msg;
+	void *hdr;
+	int ret;
+
+	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+	p.msg = msg;
+
+	hdr = genlmsg_put_reply(msg, info, &dpll_gnl_family, 0, cmd);
+	if (!hdr) {
+		ret = -EMSGSIZE;
+		goto out_free_msg;
+	}
+
+	ret = cmd_doit_cb[cmd](&p);
+	if (ret)
+		goto out_cancel_msg;
+
+	genlmsg_end(msg, hdr);
+
+	return genlmsg_reply(msg, info);
+
+out_cancel_msg:
+	genlmsg_cancel(msg, hdr);
+out_free_msg:
+	nlmsg_free(msg);
+
+	return ret;
+}
+
+static int dpll_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
+						 struct genl_info *info)
+{
+	struct dpll_device *dpll;
+	int id;
+
+	if (!info->attrs[DPLLA_DEVICE_ID])
+		return -EINVAL;
+	id = nla_get_u32(info->attrs[DPLLA_DEVICE_ID]);
+
+	dpll = dpll_device_get_by_id(id);
+	if (!dpll)
+		return -ENODEV;
+	info->user_ptr[0] = dpll;
+
+	return 0;
+}
+
+static const struct genl_ops dpll_genl_ops[] = {
+	{
+		.cmd	= DPLL_CMD_DEVICE_GET,
+		.start	= dpll_genl_cmd_start,
+		.dumpit	= dpll_genl_cmd_dumpit,
+		.doit	= dpll_genl_cmd_doit,
+		.policy	= dpll_genl_get_policy,
+		.maxattr = ARRAY_SIZE(dpll_genl_get_policy) - 1,
+	},
+	{
+		.cmd	= DPLL_CMD_SET_SOURCE_TYPE,
+		.flags	= GENL_UNS_ADMIN_PERM,
+		.doit	= dpll_genl_cmd_doit,
+		.policy	= dpll_genl_set_source_policy,
+		.maxattr = ARRAY_SIZE(dpll_genl_set_source_policy) - 1,
+	},
+	{
+		.cmd	= DPLL_CMD_SET_OUTPUT_TYPE,
+		.flags	= GENL_UNS_ADMIN_PERM,
+		.doit	= dpll_genl_cmd_doit,
+		.policy	= dpll_genl_set_output_policy,
+		.maxattr = ARRAY_SIZE(dpll_genl_set_output_policy) - 1,
+	},
+};
+
+static struct genl_family dpll_gnl_family __ro_after_init = {
+	.hdrsize	= 0,
+	.name		= DPLL_FAMILY_NAME,
+	.version	= DPLL_VERSION,
+	.ops		= dpll_genl_ops,
+	.n_ops		= ARRAY_SIZE(dpll_genl_ops),
+	.mcgrps		= dpll_genl_mcgrps,
+	.n_mcgrps	= ARRAY_SIZE(dpll_genl_mcgrps),
+};
+
+int __init dpll_netlink_init(void)
+{
+	return genl_register_family(&dpll_gnl_family);
+}
+
+void dpll_netlink_finish(void)
+{
+	genl_unregister_family(&dpll_gnl_family);
+}
+
+void __exit dpll_netlink_fini(void)
+{
+	dpll_netlink_finish();
+}
diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h
new file mode 100644
index 000000000000..e2d100f59dd6
--- /dev/null
+++ b/drivers/dpll/dpll_netlink.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright (c) 2021 Meta Platforms, Inc. and affiliates
+ */
+
+int __init dpll_netlink_init(void);
+void dpll_netlink_finish(void);
diff --git a/include/linux/dpll.h b/include/linux/dpll.h
new file mode 100644
index 000000000000..9abc428cb103
--- /dev/null
+++ b/include/linux/dpll.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright (c) 2021 Meta Platforms, Inc. and affiliates
+ */
+
+#ifndef __DPLL_H__
+#define __DPLL_H__
+
+struct dpll_device;
+
+struct dpll_device_ops {
+	int (*get_status)(struct dpll_device *dpll);
+	int (*get_temp)(struct dpll_device *dpll);
+	int (*get_lock_status)(struct dpll_device *dpll);
+	int (*get_source_type)(struct dpll_device *dpll, int id);
+	int (*get_output_type)(struct dpll_device *dpll, int id);
+	int (*set_source_type)(struct dpll_device *dpll, int id, int val);
+	int (*set_output_type)(struct dpll_device *dpll, int id, int val);
+};
+
+struct dpll_device *dpll_device_alloc(struct dpll_device_ops *ops, int sources_count,
+					 int outputs_count);
+void dpll_device_register(struct dpll_device *dpll);
+#endif
diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h
new file mode 100644
index 000000000000..8c00f52736ee
--- /dev/null
+++ b/include/uapi/linux/dpll.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_DPLL_H
+#define _UAPI_LINUX_DPLL_H
+
+#define DPLL_NAME_LENGTH	20
+
+/* Adding event notification support elements */
+#define DPLL_FAMILY_NAME		"dpll"
+#define DPLL_VERSION			0x01
+#define DPLL_CONFIG_DEVICE_GROUP_NAME  "config"
+#define DPLL_CONFIG_SOURCE_GROUP_NAME  "source"
+#define DPLL_CONFIG_OUTPUT_GROUP_NAME  "output"
+#define DPLL_MONITOR_GROUP_NAME        "monitor"
+
+#define DPLL_FLAG_SOURCES	1
+#define DPLL_FLAG_OUTPUTS	2
+#define DPLL_FLAG_STATUS	4
+
+/* Attributes of dpll_genl_family */
+enum dpll_genl_get_attr {
+	DPLLA_UNSPEC,
+	DPLLA_DEVICE,
+	DPLLA_DEVICE_ID,
+	DPLLA_DEVICE_NAME,
+	DPLLA_SOURCE,
+	DPLLA_SOURCE_ID,
+	DPLLA_SOURCE_TYPE,
+	DPLLA_OUTPUT,
+	DPLLA_OUTPUT_ID,
+	DPLLA_OUTPUT_TYPE,
+	DPLLA_STATUS,
+	DPLLA_TEMP,
+	DPLLA_LOCK_STATUS,
+	DPLLA_FLAGS,
+
+	__DPLLA_MAX,
+};
+#define DPLLA_GET_MAX (__DPLLA_MAX - 1)
+
+/* DPLL signal types used as source or as output */
+enum dpll_genl_signal_type {
+	DPLL_TYPE_EXT_1PPS,
+	DPLL_TYPE_EXT_10MHZ,
+	DPLL_TYPE_SYNCE_ETH_PORT,
+	DPLL_TYPE_INT_OSCILLATOR,
+	DPLL_TYPE_GNSS,
+
+	__DPLL_TYPE_MAX,
+};
+#define DPLL_TYPE_MAX (__DPLL_TYPE_MAX - 1)
+
+/* Events of dpll_genl_family */
+enum dpll_genl_event {
+	DPLL_EVENT_UNSPEC,
+	DPLL_EVENT_DEVICE_CREATE,		/* DPLL device creation */
+	DPLL_EVENT_DEVICE_DELETE,		/* DPLL device deletion */
+	DPLL_EVENT_STATUS_LOCKED,		/* DPLL device locked to source */
+	DPLL_EVENT_STATUS_UNLOCKED,	/* DPLL device freerun */
+	DPLL_EVENT_SOURCE_CHANGE,		/* DPLL device source changed */
+	DPLL_EVENT_OUTPUT_CHANGE,		/* DPLL device output changed */
+
+	__DPLL_EVENT_MAX,
+};
+#define DPLL_EVENT_MAX (__DPLL_EVENT_MAX - 1)
+
+/* Commands supported by the dpll_genl_family */
+enum dpll_genl_cmd {
+	DPLL_CMD_UNSPEC,
+	DPLL_CMD_DEVICE_GET,	/* List of DPLL devices id */
+	DPLL_CMD_SET_SOURCE_TYPE,	/* Set the DPLL device source type */
+	DPLL_CMD_SET_OUTPUT_TYPE,	/* Get the DPLL device output type */
+
+	__DPLL_CMD_MAX,
+};
+#define DPLL_CMD_MAX (__DPLL_CMD_MAX - 1)
+
+#endif /* _UAPI_LINUX_DPLL_H */
-- 
2.27.0


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

* [RFC PATCH 2/3] dpll: add netlink events
  2022-06-22  0:06 [RFC PATCH 0/3] Create common DPLL/clock configuration API Vadim Fedorenko
  2022-06-22  0:06 ` [RFC PATCH 1/3] dpll: Add DPLL framework base functions Vadim Fedorenko
@ 2022-06-22  0:06 ` Vadim Fedorenko
  2022-06-22  0:06 ` [RFC PATCH 3/3] ptp_ocp: implement DPLL ops Vadim Fedorenko
  2 siblings, 0 replies; 6+ messages in thread
From: Vadim Fedorenko @ 2022-06-22  0:06 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Vadim Fedorenko, Aya Levin, Arkadiusz Kubalewski, netdev,
	linux-arm-kernel

From: Vadim Fedorenko <vadfed@fb.com>

Add netlink interface to enable notification of users about
events in DPLL framework. Part of this interface should be
used by drivers directly, i.e. lock status changes.

Signed-off-by: Vadim Fedorenko <vadfed@fb.com>
---
 drivers/dpll/dpll_core.c    |   2 +
 drivers/dpll/dpll_netlink.c | 147 ++++++++++++++++++++++++++++++++++++
 drivers/dpll/dpll_netlink.h |   7 ++
 3 files changed, 156 insertions(+)

diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c
index a6d6ea828073..075dfdfa370e 100644
--- a/drivers/dpll/dpll_core.c
+++ b/drivers/dpll/dpll_core.c
@@ -94,6 +94,8 @@ struct dpll_device *dpll_device_alloc(struct dpll_device_ops *ops, int sources_c
 	mutex_unlock(&dpll_device_xa_lock);
 	dpll->priv = priv;
 
+	dpll_notify_device_create(dpll->id, dev_name(&dpll->dev));
+
 	return dpll;
 
 error:
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index 85a4b0c8c2f2..e11727028103 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -48,6 +48,8 @@ struct param {
 	int dpll_source_type;
 	int dpll_output_id;
 	int dpll_output_type;
+	int dpll_status;
+	const char *dpll_name;
 };
 
 struct dpll_dump_ctx {
@@ -222,6 +224,8 @@ static int dpll_genl_cmd_set_source(struct param *p)
 	ret = dpll->ops->set_source_type(dpll, src_id, type);
 	mutex_unlock(&dpll->lock);
 
+	dpll_notify_source_change(id, src_id, type);
+
 	return ret;
 }
 
@@ -245,6 +249,8 @@ static int dpll_genl_cmd_set_output(struct param *p)
 	ret = dpll->ops->set_source_type(dpll, out_id, type);
 	mutex_unlock(&dpll->lock);
 
+	dpll_notify_source_change(id, out_id, type);
+
 	return ret;
 }
 
@@ -420,6 +426,147 @@ static struct genl_family dpll_gnl_family __ro_after_init = {
 	.n_mcgrps	= ARRAY_SIZE(dpll_genl_mcgrps),
 };
 
+static int dpll_event_device_create(struct param *p)
+{
+	if (nla_put_u32(p->msg, DPLLA_DEVICE_ID, p->dpll_id) ||
+	    nla_put_string(p->msg, DPLLA_DEVICE_NAME, p->dpll_name))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int dpll_event_device_delete(struct param *p)
+{
+	if (nla_put_u32(p->msg, DPLLA_DEVICE_ID, p->dpll_id))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int dpll_event_status(struct param *p)
+{
+	if (nla_put_u32(p->msg, DPLLA_DEVICE_ID, p->dpll_id) ||
+		nla_put_u32(p->msg, DPLLA_LOCK_STATUS, p->dpll_status))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int dpll_event_source_change(struct param *p)
+{
+	if (nla_put_u32(p->msg, DPLLA_DEVICE_ID, p->dpll_id) ||
+	    nla_put_u32(p->msg, DPLLA_SOURCE_ID, p->dpll_source_id) ||
+		nla_put_u32(p->msg, DPLLA_SOURCE_TYPE, p->dpll_source_type))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int dpll_event_output_change(struct param *p)
+{
+	if (nla_put_u32(p->msg, DPLLA_DEVICE_ID, p->dpll_id) ||
+	    nla_put_u32(p->msg, DPLLA_OUTPUT_ID, p->dpll_output_id) ||
+		nla_put_u32(p->msg, DPLLA_OUTPUT_TYPE, p->dpll_output_type))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+int dpll_event_status_lock(struct param *p)
+	__alias("dpll_event_status");
+
+int dpll_event_status_unlock(struct param *p)
+	__alias("dpll_event_status");
+
+static cb_t event_cb[] = {
+	[DPLL_EVENT_DEVICE_CREATE]	= dpll_event_device_create,
+	[DPLL_EVENT_DEVICE_DELETE]	= dpll_event_device_delete,
+	[DPLL_EVENT_STATUS_LOCKED]	= dpll_event_status_lock,
+	[DPLL_EVENT_STATUS_UNLOCKED]	= dpll_event_status_unlock,
+	[DPLL_EVENT_SOURCE_CHANGE]	= dpll_event_source_change,
+	[DPLL_EVENT_OUTPUT_CHANGE]	= dpll_event_output_change,
+};
+/*
+ * Generic netlink DPLL event encoding
+ */
+static int dpll_send_event(enum dpll_genl_event event,
+				   struct param *p)
+{
+	struct sk_buff *msg;
+	int ret = -EMSGSIZE;
+	void *hdr;
+
+	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+	p->msg = msg;
+
+	hdr = genlmsg_put(msg, 0, 0, &dpll_gnl_family, 0, event);
+	if (!hdr)
+		goto out_free_msg;
+
+	ret = event_cb[event](p);
+	if (ret)
+		goto out_cancel_msg;
+
+	genlmsg_end(msg, hdr);
+
+	genlmsg_multicast(&dpll_gnl_family, msg, 0, 1, GFP_KERNEL);
+
+	return 0;
+
+out_cancel_msg:
+	genlmsg_cancel(msg, hdr);
+out_free_msg:
+	nlmsg_free(msg);
+
+	return ret;
+}
+
+int dpll_notify_device_create(int dpll_id, const char *name)
+{
+	struct param p = { .dpll_id = dpll_id, .dpll_name = name };
+
+	return dpll_send_event(DPLL_EVENT_DEVICE_CREATE, &p);
+}
+
+int dpll_notify_device_delete(int dpll_id)
+{
+	struct param p = { .dpll_id = dpll_id };
+
+	return dpll_send_event(DPLL_EVENT_DEVICE_DELETE, &p);
+}
+
+int dpll_notify_status_locked(int dpll_id)
+{
+	struct param p = { .dpll_id = dpll_id, .dpll_status = 1 };
+
+	return dpll_send_event(DPLL_EVENT_STATUS_LOCKED, &p);
+}
+
+int dpll_notify_status_unlocked(int dpll_id)
+{
+	struct param p = { .dpll_id = dpll_id, .dpll_status = 0 };
+
+	return dpll_send_event(DPLL_EVENT_STATUS_UNLOCKED, &p);
+}
+
+int dpll_notify_source_change(int dpll_id, int source_id, int source_type)
+{
+	struct param p =  { .dpll_id = dpll_id, .dpll_source_id = source_id,
+						.dpll_source_type = source_type };
+
+	return dpll_send_event(DPLL_EVENT_SOURCE_CHANGE, &p);
+}
+
+int dpll_notify_output_change(int dpll_id, int output_id, int output_type)
+{
+	struct param p =  { .dpll_id = dpll_id, .dpll_output_id = output_id,
+						.dpll_output_type = output_type };
+
+	return dpll_send_event(DPLL_EVENT_OUTPUT_CHANGE, &p);
+}
+
 int __init dpll_netlink_init(void)
 {
 	return genl_register_family(&dpll_gnl_family);
diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h
index e2d100f59dd6..0dc81320f982 100644
--- a/drivers/dpll/dpll_netlink.h
+++ b/drivers/dpll/dpll_netlink.h
@@ -3,5 +3,12 @@
  *  Copyright (c) 2021 Meta Platforms, Inc. and affiliates
  */
 
+int dpll_notify_device_create(int dpll_id, const char *name);
+int dpll_notify_device_delete(int dpll_id);
+int dpll_notify_status_locked(int dpll_id);
+int dpll_notify_status_unlocked(int dpll_id);
+int dpll_notify_source_change(int dpll_id, int source_id, int source_type);
+int dpll_notify_output_change(int dpll_id, int output_id, int output_type);
+
 int __init dpll_netlink_init(void);
 void dpll_netlink_finish(void);
-- 
2.27.0


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

* [RFC PATCH 3/3] ptp_ocp: implement DPLL ops
  2022-06-22  0:06 [RFC PATCH 0/3] Create common DPLL/clock configuration API Vadim Fedorenko
  2022-06-22  0:06 ` [RFC PATCH 1/3] dpll: Add DPLL framework base functions Vadim Fedorenko
  2022-06-22  0:06 ` [RFC PATCH 2/3] dpll: add netlink events Vadim Fedorenko
@ 2022-06-22  0:06 ` Vadim Fedorenko
  2022-06-22  6:16   ` kernel test robot
  2022-06-22 10:27   ` kernel test robot
  2 siblings, 2 replies; 6+ messages in thread
From: Vadim Fedorenko @ 2022-06-22  0:06 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Vadim Fedorenko, Aya Levin, Arkadiusz Kubalewski, netdev,
	linux-arm-kernel

From: Vadim Fedorenko <vadfed@fb.com>

Implement DPLL operations in ptp_ocp driver.

Signed-off-by: Vadim Fedorenko <vadfed@fb.com>
---
 drivers/ptp/Kconfig   |  1 +
 drivers/ptp/ptp_ocp.c | 85 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+)

diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 458218f88c5e..f74846ebc177 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -176,6 +176,7 @@ config PTP_1588_CLOCK_OCP
 	depends on !S390
 	depends on COMMON_CLK
 	select NET_DEVLINK
+	select DPLL
 	help
 	  This driver adds support for an OpenCompute time card.
 
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index e59ea2173aac..b7bdb210514d 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -21,6 +21,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/nvmem-consumer.h>
 #include <linux/crc16.h>
+#include <uapi/linux/dpll.h>
 
 #define PCI_VENDOR_ID_FACEBOOK			0x1d9b
 #define PCI_DEVICE_ID_FACEBOOK_TIMECARD		0x0400
@@ -336,6 +337,7 @@ struct ptp_ocp {
 	struct ptp_ocp_signal	signal[4];
 	struct ptp_ocp_sma_connector sma[4];
 	const struct ocp_sma_op *sma_op;
+	struct dpll_device *dpll;
 };
 
 #define OCP_REQ_TIMESTAMP	BIT(0)
@@ -3713,6 +3715,81 @@ ptp_ocp_detach(struct ptp_ocp *bp)
 	device_unregister(&bp->dev);
 }
 
+static int ptp_ocp_dpll_get_status(struct dpll_device *dpll)
+{
+	struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
+	int sync;
+
+	sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC;
+	return sync;
+}
+
+static int ptp_ocp_dpll_get_lock_status(struct dpll_device *dpll)
+{
+	struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
+	int sync;
+
+	sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC;
+	return sync;
+}
+
+static int ptp_ocp_dpll_get_source_type(struct dpll_device *dpll, int sma)
+{
+	struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
+	int ret;
+
+	if (bp->sma[sma].mode != SMA_MODE_IN)
+		return -1;
+
+	switch (ptp_ocp_sma_get(bp, sma)) {
+	case 0:
+		ret = DPLL_TYPE_EXT_10MHZ;
+		break;
+	case 1:
+	case 2:
+		ret = DPLL_TYPE_EXT_1PPS;
+		break;
+	default:
+		ret = DPLL_TYPE_INT_OSCILLATOR;
+	}
+
+	return ret;
+}
+
+
+static int ptp_ocp_dpll_get_output_type(struct dpll_device *dpll, int sma)
+{
+	struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
+	int ret;
+
+	if (bp->sma[sma].mode != SMA_MODE_IN)
+		return -1;
+
+	switch (ptp_ocp_sma_get(bp, sma)) {
+	case 0:
+		ret = DPLL_TYPE_EXT_10MHZ;
+		break;
+	case 1:
+	case 2:
+		ret = DPLL_TYPE_INT_OSCILLATOR;
+	case 4:
+	case 8:
+		ret = DPLL_TYPE_GNSS;
+		break;
+	default:
+		ret = DPLL_TYPE_INT_OSCILLATOR;
+	}
+
+	return ret;
+}
+
+static struct dpll_device_ops ptp_ocp_dpll_ops {
+	.get_status			= ptp_ocp_dpll_get_status;
+	.get_lock_status	= ptp_ocp_dpll_get_lock_status;
+	.get_source_type	= ptp_ocp_dpll_get_source_type;
+	.get_output_type	= ptp_ocp_dpll_get_output_type;
+};
+
 static int
 ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -3768,6 +3845,14 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	ptp_ocp_info(bp);
 	devlink_register(devlink);
+
+	bp->dpll = dpll_device_alloc(&dpll_ops, ARRAY_SIZE(bp->sma), ARRAY_SIZE(bp->sma));
+	if (!bp->dpll) {
+		dev_err(&pdev->dev, "dpll_device_alloc failed\n");
+		return 0;
+	}
+	dpll_device_register(bp->dpll);
+
 	return 0;
 
 out:
-- 
2.27.0


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

* Re: [RFC PATCH 3/3] ptp_ocp: implement DPLL ops
  2022-06-22  0:06 ` [RFC PATCH 3/3] ptp_ocp: implement DPLL ops Vadim Fedorenko
@ 2022-06-22  6:16   ` kernel test robot
  2022-06-22 10:27   ` kernel test robot
  1 sibling, 0 replies; 6+ messages in thread
From: kernel test robot @ 2022-06-22  6:16 UTC (permalink / raw)
  To: Vadim Fedorenko; +Cc: llvm, kbuild-all

Hi Vadim,

[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on linus/master]
[also build test WARNING on v5.19-rc3 next-20220621]
[cannot apply to horms-ipvs/master]
[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]

url:    https://github.com/intel-lab-lkp/linux/commits/Vadim-Fedorenko/Create-common-DPLL-clock-configuration-API/20220622-080746
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git ca1fdab7fd27eb069df1384b2850dcd0c2bebe8d
config: x86_64-randconfig-a005 (https://download.01.org/0day-ci/archive/20220622/202206221441.9L8YTI3Y-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 8b8d126598ce7bd5243da7f94f69fa1104288bee)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/bb2b52ab297193cfb419e71db72823a36b11e031
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Vadim-Fedorenko/Create-common-DPLL-clock-configuration-API/20220622-080746
        git checkout bb2b52ab297193cfb419e71db72823a36b11e031
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/dpll/ drivers/ptp/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/dpll/dpll_netlink.c:227:28: error: use of undeclared identifier 'id'
           dpll_notify_source_change(id, src_id, type);
                                     ^
   drivers/dpll/dpll_netlink.c:252:28: error: use of undeclared identifier 'id'
           dpll_notify_source_change(id, out_id, type);
                                     ^
>> drivers/dpll/dpll_netlink.c:580:13: warning: no previous prototype for function 'dpll_netlink_fini' [-Wmissing-prototypes]
   void __exit dpll_netlink_fini(void)
               ^
   drivers/dpll/dpll_netlink.c:580:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void __exit dpll_netlink_fini(void)
   ^
   static 
   1 warning and 2 errors generated.
--
   drivers/ptp/ptp_ocp.c:3721:45: error: incomplete definition of type 'struct dpll_device'
           struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
                                                  ~~~~^
   drivers/ptp/ptp_ocp.c:339:9: note: forward declaration of 'struct dpll_device'
           struct dpll_device *dpll;
                  ^
   drivers/ptp/ptp_ocp.c:3730:45: error: incomplete definition of type 'struct dpll_device'
           struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
                                                  ~~~~^
   drivers/ptp/ptp_ocp.c:339:9: note: forward declaration of 'struct dpll_device'
           struct dpll_device *dpll;
                  ^
   drivers/ptp/ptp_ocp.c:3739:45: error: incomplete definition of type 'struct dpll_device'
           struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
                                                  ~~~~^
   drivers/ptp/ptp_ocp.c:339:9: note: forward declaration of 'struct dpll_device'
           struct dpll_device *dpll;
                  ^
   drivers/ptp/ptp_ocp.c:3763:45: error: incomplete definition of type 'struct dpll_device'
           struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
                                                  ~~~~^
   drivers/ptp/ptp_ocp.c:339:9: note: forward declaration of 'struct dpll_device'
           struct dpll_device *dpll;
                  ^
>> drivers/ptp/ptp_ocp.c:3787:31: warning: tentative definition of variable with internal linkage has incomplete non-array type 'struct dpll_device_ops' [-Wtentative-definition-incomplete-type]
   static struct dpll_device_ops ptp_ocp_dpll_ops {
                                 ^
   drivers/ptp/ptp_ocp.c:3787:15: note: forward declaration of 'struct dpll_device_ops'
   static struct dpll_device_ops ptp_ocp_dpll_ops {
                 ^
   drivers/ptp/ptp_ocp.c:3787:47: error: expected ';' after top level declarator
   static struct dpll_device_ops ptp_ocp_dpll_ops {
                                                 ^
                                                 ;
   drivers/ptp/ptp_ocp.c:3850:13: error: call to undeclared function 'dpll_device_alloc'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
           bp->dpll = dpll_device_alloc(&dpll_ops, ARRAY_SIZE(bp->sma), ARRAY_SIZE(bp->sma));
                      ^
   drivers/ptp/ptp_ocp.c:3850:32: error: use of undeclared identifier 'dpll_ops'
           bp->dpll = dpll_device_alloc(&dpll_ops, ARRAY_SIZE(bp->sma), ARRAY_SIZE(bp->sma));
                                         ^
   drivers/ptp/ptp_ocp.c:3855:2: error: call to undeclared function 'dpll_device_register'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
           dpll_device_register(bp->dpll);
           ^
   drivers/ptp/ptp_ocp.c:3855:2: note: did you mean 'device_register'?
   include/linux/device.h:895:18: note: 'device_register' declared here
   int __must_check device_register(struct device *dev);
                    ^
   drivers/ptp/ptp_ocp.c:3787:31: error: tentative definition has type 'struct dpll_device_ops' that is never completed
   static struct dpll_device_ops ptp_ocp_dpll_ops {
                                 ^
   drivers/ptp/ptp_ocp.c:3787:15: note: forward declaration of 'struct dpll_device_ops'
   static struct dpll_device_ops ptp_ocp_dpll_ops {
                 ^
   1 warning and 9 errors generated.


vim +3787 drivers/ptp/ptp_ocp.c

  3786	
> 3787	static struct dpll_device_ops ptp_ocp_dpll_ops {
  3788		.get_status			= ptp_ocp_dpll_get_status;
  3789		.get_lock_status	= ptp_ocp_dpll_get_lock_status;
  3790		.get_source_type	= ptp_ocp_dpll_get_source_type;
  3791		.get_output_type	= ptp_ocp_dpll_get_output_type;
  3792	};
  3793	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

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

* Re: [RFC PATCH 3/3] ptp_ocp: implement DPLL ops
  2022-06-22  0:06 ` [RFC PATCH 3/3] ptp_ocp: implement DPLL ops Vadim Fedorenko
  2022-06-22  6:16   ` kernel test robot
@ 2022-06-22 10:27   ` kernel test robot
  1 sibling, 0 replies; 6+ messages in thread
From: kernel test robot @ 2022-06-22 10:27 UTC (permalink / raw)
  To: Vadim Fedorenko; +Cc: llvm, kbuild-all

Hi Vadim,

[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on linus/master]
[also build test ERROR on v5.19-rc3 next-20220622]
[cannot apply to horms-ipvs/master]
[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]

url:    https://github.com/intel-lab-lkp/linux/commits/Vadim-Fedorenko/Create-common-DPLL-clock-configuration-API/20220622-080746
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git ca1fdab7fd27eb069df1384b2850dcd0c2bebe8d
config: x86_64-randconfig-a005 (https://download.01.org/0day-ci/archive/20220622/202206221822.9TNJ02fp-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 8b8d126598ce7bd5243da7f94f69fa1104288bee)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/bb2b52ab297193cfb419e71db72823a36b11e031
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Vadim-Fedorenko/Create-common-DPLL-clock-configuration-API/20220622-080746
        git checkout bb2b52ab297193cfb419e71db72823a36b11e031
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/ptp/ptp_ocp.c:3721:45: error: incomplete definition of type 'struct dpll_device'
           struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
                                                  ~~~~^
   drivers/ptp/ptp_ocp.c:339:9: note: forward declaration of 'struct dpll_device'
           struct dpll_device *dpll;
                  ^
   drivers/ptp/ptp_ocp.c:3730:45: error: incomplete definition of type 'struct dpll_device'
           struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
                                                  ~~~~^
   drivers/ptp/ptp_ocp.c:339:9: note: forward declaration of 'struct dpll_device'
           struct dpll_device *dpll;
                  ^
   drivers/ptp/ptp_ocp.c:3739:45: error: incomplete definition of type 'struct dpll_device'
           struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
                                                  ~~~~^
   drivers/ptp/ptp_ocp.c:339:9: note: forward declaration of 'struct dpll_device'
           struct dpll_device *dpll;
                  ^
   drivers/ptp/ptp_ocp.c:3763:45: error: incomplete definition of type 'struct dpll_device'
           struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
                                                  ~~~~^
   drivers/ptp/ptp_ocp.c:339:9: note: forward declaration of 'struct dpll_device'
           struct dpll_device *dpll;
                  ^
   drivers/ptp/ptp_ocp.c:3787:31: warning: tentative definition of variable with internal linkage has incomplete non-array type 'struct dpll_device_ops' [-Wtentative-definition-incomplete-type]
   static struct dpll_device_ops ptp_ocp_dpll_ops {
                                 ^
   drivers/ptp/ptp_ocp.c:3787:15: note: forward declaration of 'struct dpll_device_ops'
   static struct dpll_device_ops ptp_ocp_dpll_ops {
                 ^
>> drivers/ptp/ptp_ocp.c:3787:47: error: expected ';' after top level declarator
   static struct dpll_device_ops ptp_ocp_dpll_ops {
                                                 ^
                                                 ;
>> drivers/ptp/ptp_ocp.c:3850:13: error: call to undeclared function 'dpll_device_alloc'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
           bp->dpll = dpll_device_alloc(&dpll_ops, ARRAY_SIZE(bp->sma), ARRAY_SIZE(bp->sma));
                      ^
>> drivers/ptp/ptp_ocp.c:3850:32: error: use of undeclared identifier 'dpll_ops'
           bp->dpll = dpll_device_alloc(&dpll_ops, ARRAY_SIZE(bp->sma), ARRAY_SIZE(bp->sma));
                                         ^
>> drivers/ptp/ptp_ocp.c:3855:2: error: call to undeclared function 'dpll_device_register'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
           dpll_device_register(bp->dpll);
           ^
   drivers/ptp/ptp_ocp.c:3855:2: note: did you mean 'device_register'?
   include/linux/device.h:895:18: note: 'device_register' declared here
   int __must_check device_register(struct device *dev);
                    ^
>> drivers/ptp/ptp_ocp.c:3787:31: error: tentative definition has type 'struct dpll_device_ops' that is never completed
   static struct dpll_device_ops ptp_ocp_dpll_ops {
                                 ^
   drivers/ptp/ptp_ocp.c:3787:15: note: forward declaration of 'struct dpll_device_ops'
   static struct dpll_device_ops ptp_ocp_dpll_ops {
                 ^
   1 warning and 9 errors generated.
--
   drivers/dpll/dpll_core.c:19:28: error: redefinition of 'dpll_device_xa'
   static DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC);
                              ^
   drivers/dpll/dpll_core.c:18:28: note: previous definition is here
   static DEFINE_XARRAY_ALLOC(dpll_device_xa);
                              ^
>> drivers/dpll/dpll_core.c:37:4: error: expected ')'
                           continue;
                           ^
   drivers/dpll/dpll_core.c:36:6: note: to match this '('
                   if (!xa_get_mark(&dpll_device_xa, index, DPLL_REGISTERED)
                      ^
>> drivers/dpll/dpll_core.c:73:21: error: conflicting types for 'dpll_device_alloc'
   struct dpll_device *dpll_device_alloc(struct dpll_device_ops *ops, int sources_count,
                       ^
   include/linux/dpll.h:21:21: note: previous declaration is here
   struct dpll_device *dpll_device_alloc(struct dpll_device_ops *ops, int sources_count,
                       ^
   3 errors generated.
--
>> drivers/dpll/dpll_netlink.c:227:28: error: use of undeclared identifier 'id'
           dpll_notify_source_change(id, src_id, type);
                                     ^
   drivers/dpll/dpll_netlink.c:252:28: error: use of undeclared identifier 'id'
           dpll_notify_source_change(id, out_id, type);
                                     ^
   drivers/dpll/dpll_netlink.c:580:13: warning: no previous prototype for function 'dpll_netlink_fini' [-Wmissing-prototypes]
   void __exit dpll_netlink_fini(void)
               ^
   drivers/dpll/dpll_netlink.c:580:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void __exit dpll_netlink_fini(void)
   ^
   static 
   1 warning and 2 errors generated.


vim +3721 drivers/ptp/ptp_ocp.c

  3718	
  3719	static int ptp_ocp_dpll_get_status(struct dpll_device *dpll)
  3720	{
> 3721		struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
  3722		int sync;
  3723	
  3724		sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC;
  3725		return sync;
  3726	}
  3727	
  3728	static int ptp_ocp_dpll_get_lock_status(struct dpll_device *dpll)
  3729	{
  3730		struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
  3731		int sync;
  3732	
  3733		sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC;
  3734		return sync;
  3735	}
  3736	
  3737	static int ptp_ocp_dpll_get_source_type(struct dpll_device *dpll, int sma)
  3738	{
  3739		struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
  3740		int ret;
  3741	
  3742		if (bp->sma[sma].mode != SMA_MODE_IN)
  3743			return -1;
  3744	
  3745		switch (ptp_ocp_sma_get(bp, sma)) {
  3746		case 0:
  3747			ret = DPLL_TYPE_EXT_10MHZ;
  3748			break;
  3749		case 1:
  3750		case 2:
  3751			ret = DPLL_TYPE_EXT_1PPS;
  3752			break;
  3753		default:
  3754			ret = DPLL_TYPE_INT_OSCILLATOR;
  3755		}
  3756	
  3757		return ret;
  3758	}
  3759	
  3760	
  3761	static int ptp_ocp_dpll_get_output_type(struct dpll_device *dpll, int sma)
  3762	{
  3763		struct ptp_ocp *bp = (struct ptp_ocp *)dpll->priv;
  3764		int ret;
  3765	
  3766		if (bp->sma[sma].mode != SMA_MODE_IN)
  3767			return -1;
  3768	
  3769		switch (ptp_ocp_sma_get(bp, sma)) {
  3770		case 0:
  3771			ret = DPLL_TYPE_EXT_10MHZ;
  3772			break;
  3773		case 1:
  3774		case 2:
  3775			ret = DPLL_TYPE_INT_OSCILLATOR;
  3776		case 4:
  3777		case 8:
  3778			ret = DPLL_TYPE_GNSS;
  3779			break;
  3780		default:
  3781			ret = DPLL_TYPE_INT_OSCILLATOR;
  3782		}
  3783	
  3784		return ret;
  3785	}
  3786	
> 3787	static struct dpll_device_ops ptp_ocp_dpll_ops {
  3788		.get_status			= ptp_ocp_dpll_get_status;
  3789		.get_lock_status	= ptp_ocp_dpll_get_lock_status;
  3790		.get_source_type	= ptp_ocp_dpll_get_source_type;
  3791		.get_output_type	= ptp_ocp_dpll_get_output_type;
  3792	};
  3793	
  3794	static int
  3795	ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
  3796	{
  3797		struct devlink *devlink;
  3798		struct ptp_ocp *bp;
  3799		int err;
  3800	
  3801		devlink = devlink_alloc(&ptp_ocp_devlink_ops, sizeof(*bp), &pdev->dev);
  3802		if (!devlink) {
  3803			dev_err(&pdev->dev, "devlink_alloc failed\n");
  3804			return -ENOMEM;
  3805		}
  3806	
  3807		err = pci_enable_device(pdev);
  3808		if (err) {
  3809			dev_err(&pdev->dev, "pci_enable_device\n");
  3810			goto out_free;
  3811		}
  3812	
  3813		bp = devlink_priv(devlink);
  3814		err = ptp_ocp_device_init(bp, pdev);
  3815		if (err)
  3816			goto out_disable;
  3817	
  3818		/* compat mode.
  3819		 * Older FPGA firmware only returns 2 irq's.
  3820		 * allow this - if not all of the IRQ's are returned, skip the
  3821		 * extra devices and just register the clock.
  3822		 */
  3823		err = pci_alloc_irq_vectors(pdev, 1, 17, PCI_IRQ_MSI | PCI_IRQ_MSIX);
  3824		if (err < 0) {
  3825			dev_err(&pdev->dev, "alloc_irq_vectors err: %d\n", err);
  3826			goto out;
  3827		}
  3828		bp->n_irqs = err;
  3829		pci_set_master(pdev);
  3830	
  3831		err = ptp_ocp_register_resources(bp, id->driver_data);
  3832		if (err)
  3833			goto out;
  3834	
  3835		bp->ptp = ptp_clock_register(&bp->ptp_info, &pdev->dev);
  3836		if (IS_ERR(bp->ptp)) {
  3837			err = PTR_ERR(bp->ptp);
  3838			dev_err(&pdev->dev, "ptp_clock_register: %d\n", err);
  3839			bp->ptp = NULL;
  3840			goto out;
  3841		}
  3842	
  3843		err = ptp_ocp_complete(bp);
  3844		if (err)
  3845			goto out;
  3846	
  3847		ptp_ocp_info(bp);
  3848		devlink_register(devlink);
  3849	
> 3850		bp->dpll = dpll_device_alloc(&dpll_ops, ARRAY_SIZE(bp->sma), ARRAY_SIZE(bp->sma));
  3851		if (!bp->dpll) {
  3852			dev_err(&pdev->dev, "dpll_device_alloc failed\n");
  3853			return 0;
  3854		}
> 3855		dpll_device_register(bp->dpll);
  3856	
  3857		return 0;
  3858	
  3859	out:
  3860		ptp_ocp_detach(bp);
  3861		pci_set_drvdata(pdev, NULL);
  3862	out_disable:
  3863		pci_disable_device(pdev);
  3864	out_free:
  3865		devlink_free(devlink);
  3866		return err;
  3867	}
  3868	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

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

end of thread, other threads:[~2022-06-22 10:28 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-22  0:06 [RFC PATCH 0/3] Create common DPLL/clock configuration API Vadim Fedorenko
2022-06-22  0:06 ` [RFC PATCH 1/3] dpll: Add DPLL framework base functions Vadim Fedorenko
2022-06-22  0:06 ` [RFC PATCH 2/3] dpll: add netlink events Vadim Fedorenko
2022-06-22  0:06 ` [RFC PATCH 3/3] ptp_ocp: implement DPLL ops Vadim Fedorenko
2022-06-22  6:16   ` kernel test robot
2022-06-22 10:27   ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.