File Index
Files and directories
Sign in
FILE

coresight-dummy.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hwtracing/coresight/coresight-dummy.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  4 */
  5
  6#include <linux/coresight.h>
  7#include <linux/kernel.h>
  8#include <linux/module.h>
  9#include <linux/of.h>
 10#include <linux/platform_device.h>
 11#include <linux/pm_runtime.h>
 12
 13#include "coresight-priv.h"
 14#include "coresight-trace-id.h"
 15
 16struct dummy_drvdata {
 17	struct device			*dev;
 18	struct coresight_device		*csdev;
 19	u8				traceid;
 20};
 21
 22DEFINE_CORESIGHT_DEVLIST(source_devs, "dummy_source");
 23DEFINE_CORESIGHT_DEVLIST(sink_devs, "dummy_sink");
 24
 25static int dummy_source_enable(struct coresight_device *csdev,
 26			       struct perf_event *event, enum cs_mode mode,
 27			       __maybe_unused struct coresight_path *path)
 28{
 29	if (!coresight_take_mode(csdev, mode))
 30		return -EBUSY;
 31
 32	dev_dbg(csdev->dev.parent, "Dummy source enabled\n");
 33
 34	return 0;
 35}
 36
 37static void dummy_source_disable(struct coresight_device *csdev,
 38				 struct perf_event *event)
 39{
 40	coresight_set_mode(csdev, CS_MODE_DISABLED);
 41	dev_dbg(csdev->dev.parent, "Dummy source disabled\n");
 42}
 43
 44static int dummy_source_trace_id(struct coresight_device *csdev, __maybe_unused enum cs_mode mode,
 45				 __maybe_unused struct coresight_device *sink)
 46{
 47	struct dummy_drvdata *drvdata;
 48
 49	drvdata = dev_get_drvdata(csdev->dev.parent);
 50
 51	return drvdata->traceid;
 52}
 53
 54static int dummy_sink_enable(struct coresight_device *csdev, enum cs_mode mode,
 55			     struct coresight_path *path)
 56{
 57	dev_dbg(csdev->dev.parent, "Dummy sink enabled\n");
 58
 59	return 0;
 60}
 61
 62static int dummy_sink_disable(struct coresight_device *csdev)
 63{
 64	dev_dbg(csdev->dev.parent, "Dummy sink disabled\n");
 65
 66	return 0;
 67}
 68
 69static const struct coresight_ops_source dummy_source_ops = {
 70	.enable	= dummy_source_enable,
 71	.disable = dummy_source_disable,
 72};
 73
 74static const struct coresight_ops dummy_source_cs_ops = {
 75	.trace_id	= dummy_source_trace_id,
 76	.source_ops	= &dummy_source_ops,
 77};
 78
 79static const struct coresight_ops_sink dummy_sink_ops = {
 80	.enable	= dummy_sink_enable,
 81	.disable = dummy_sink_disable,
 82};
 83
 84static const struct coresight_ops dummy_sink_cs_ops = {
 85	.sink_ops = &dummy_sink_ops,
 86};
 87
 88/* User can get the trace id of dummy source from this node. */
 89static ssize_t traceid_show(struct device *dev,
 90			    struct device_attribute *attr, char *buf)
 91{
 92	unsigned long val;
 93	struct dummy_drvdata *drvdata = dev_get_drvdata(dev->parent);
 94
 95	val = drvdata->traceid;
 96	return sysfs_emit(buf, "%#lx\n", val);
 97}
 98static DEVICE_ATTR_RO(traceid);
 99
100static struct attribute *coresight_dummy_attrs[] = {
101	&dev_attr_traceid.attr,
102	NULL,
103};
104
105static const struct attribute_group coresight_dummy_group = {
106	.attrs = coresight_dummy_attrs,
107};
108
109static const struct attribute_group *coresight_dummy_groups[] = {
110	&coresight_dummy_group,
111	NULL,
112};
113
114static int dummy_probe(struct platform_device *pdev)
115{
116	struct device *dev = &pdev->dev;
117	struct device_node *node = dev->of_node;
118	struct coresight_platform_data *pdata;
119	struct dummy_drvdata *drvdata;
120	struct coresight_desc desc = { 0 };
121	int ret = 0, trace_id = 0;
122
123	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
124	if (!drvdata)
125		return -ENOMEM;
126
127	if (of_device_is_compatible(node, "arm,coresight-dummy-source")) {
128
129		desc.name = coresight_alloc_device_name(&source_devs, dev);
130		if (!desc.name)
131			return -ENOMEM;
132
133		desc.type = CORESIGHT_DEV_TYPE_SOURCE;
134		desc.subtype.source_subtype =
135					CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS;
136		desc.ops = &dummy_source_cs_ops;
137		desc.groups = coresight_dummy_groups;
138
139		ret = coresight_get_static_trace_id(dev, &trace_id);
140		if (!ret) {
141			/* Get the static id if id is set in device tree. */
142			ret = coresight_trace_id_get_static_system_id(trace_id);
143			if (ret < 0) {
144				dev_err(dev, "Fail to get static id.\n");
145				return ret;
146			}
147		} else {
148			/* Get next available id if id is not set in device tree. */
149			trace_id = coresight_trace_id_get_system_id();
150			if (trace_id < 0) {
151				ret = trace_id;
152				return ret;
153			}
154		}
155		drvdata->traceid = (u8)trace_id;
156
157	} else if (of_device_is_compatible(node, "arm,coresight-dummy-sink")) {
158		desc.name = coresight_alloc_device_name(&sink_devs, dev);
159		if (!desc.name)
160			return -ENOMEM;
161
162		desc.type = CORESIGHT_DEV_TYPE_SINK;
163		desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_DUMMY;
164		desc.ops = &dummy_sink_cs_ops;
165	} else {
166		dev_err(dev, "Device type not set\n");
167		return -EINVAL;
168	}
169
170	pdata = coresight_get_platform_data(dev);
171	if (IS_ERR(pdata)) {
172		ret = PTR_ERR(pdata);
173		goto free_id;
174	}
175	pdev->dev.platform_data = pdata;
176
177	drvdata->dev = &pdev->dev;
178	platform_set_drvdata(pdev, drvdata);
179
180	desc.pdata = pdev->dev.platform_data;
181	desc.dev = &pdev->dev;
182	drvdata->csdev = coresight_register(&desc);
183	if (IS_ERR(drvdata->csdev)) {
184		ret = PTR_ERR(drvdata->csdev);
185		goto free_id;
186	}
187
188	pm_runtime_enable(dev);
189	dev_dbg(dev, "Dummy device initialized\n");
190
191	ret = 0;
192	goto out;
193
194free_id:
195	if (IS_VALID_CS_TRACE_ID(drvdata->traceid))
196		coresight_trace_id_put_system_id(drvdata->traceid);
197
198out:
199	return ret;
200}
201
202static void dummy_remove(struct platform_device *pdev)
203{
204	struct dummy_drvdata *drvdata = platform_get_drvdata(pdev);
205	struct device *dev = &pdev->dev;
206
207	if (IS_VALID_CS_TRACE_ID(drvdata->traceid))
208		coresight_trace_id_put_system_id(drvdata->traceid);
209	pm_runtime_disable(dev);
210	coresight_unregister(drvdata->csdev);
211}
212
213static const struct of_device_id dummy_match[] = {
214	{.compatible = "arm,coresight-dummy-source"},
215	{.compatible = "arm,coresight-dummy-sink"},
216	{},
217};
218
219static struct platform_driver dummy_driver = {
220	.probe	= dummy_probe,
221	.remove = dummy_remove,
222	.driver	= {
223		.name   = "coresight-dummy",
224		.of_match_table = dummy_match,
225	},
226};
227
228module_platform_driver(dummy_driver);
229
230MODULE_LICENSE("GPL");
231MODULE_DESCRIPTION("CoreSight dummy driver");
~/ Read-only file preview.