[PATCH 1/9 v2] coresight: add CoreSight core layer framework
From: Daniel Thompson <hidden>
Date: 2014-07-02 09:38:24
Also in:
lkml
On 27/06/14 19:04, mathieu.poirier at linaro.org wrote:
quoted hunk ↗ jump to hunk
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig new file mode 100644 index 0000000..fdd4d08 --- /dev/null +++ b/drivers/coresight/Kconfig@@ -0,0 +1,10 @@ +menuconfig CORESIGHT + bool "CoreSight Tracing Support" + select ARM_AMBA + help + This framework provides an interface for the CoreSight debug and + trace drivers to register themselves with. It's intended to build + up a topological view of the CoreSight components and configure + the right series of components on user input via sysfs. It also
I don't understand this sentence. It makes is sound like user input is needed somehow.
quoted hunk ↗ jump to hunk
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h new file mode 100644 index 0000000..da1ebbb --- /dev/null +++ b/drivers/coresight/coresight-priv.h@@ -0,0 +1,69 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CORESIGHT_PRIV_H +#define _CORESIGHT_PRIV_H + +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/coresight.h> + +/* + * Coresight management registers (0xF00-0xFCC) + * 0xFA0 - 0xFA4: Management registers in PFTv1.0 + * Trace registers in PFTv1.1 + */ +#define CORESIGHT_ITCTRL (0xF00) +#define CORESIGHT_CLAIMSET (0xFA0) +#define CORESIGHT_CLAIMCLR (0xFA4) +#define CORESIGHT_LAR (0xFB0) +#define CORESIGHT_LSR (0xFB4) +#define CORESIGHT_AUTHSTATUS (0xFB8) +#define CORESIGHT_DEVID (0xFC8) +#define CORESIGHT_DEVTYPE (0xFCC) + +#define TIMEOUT_US (100) + +#define BM(lsb, msb) ((BIT(msb) - BIT(lsb)) + BIT(msb))
Isn't this what GENMASK() already does?
+#define BMVAL(val, lsb, msb) ((val & BM(lsb, msb)) >> lsb) +#define BVAL(val, n) ((val & BIT(n)) >> n)
BVAL() is obfuscation and should be removed. As an example (taken from one of the patches that consumes this macro): + for (i = TIMEOUT_US; + BVAL(cs_readl(drvdata->base, ETB_FFCR), ETB_FFCR_BIT) != 0 + && i > 0; i--) + udelay(1); Is not really as readable as: + for (i = TIMEOUT_US; + cs_readl(drvdata->base, ETB_FFCR) & ETB_FFCR_BIT && i > 0; + i--) + udelay(1); Within the whole patchset it is only every usedIt is only ever used call site looks more or less like this:
+#define cs_writel(addr, val, off) __raw_writel((val), addr + off) +#define cs_readl(addr, off) __raw_readl(addr + off)
Out of interest, would readl/writel_relaxed() more appropriate?
quoted hunk ↗ jump to hunk
+ +static inline void CS_LOCK(void __iomem *addr) +{ + do { + /* wait for things to settle */ + mb(); + cs_writel(addr, 0x0, CORESIGHT_LAR); + } while (0); +} + +static inline void CS_UNLOCK(void __iomem *addr) +{ + do { + cs_writel(addr, CORESIGHT_UNLOCK, CORESIGHT_LAR); + /* make sure eveyone has seen this */ + mb(); + } while (0); +} + +#ifdef CONFIG_CORESIGHT_SOURCE_ETM +extern unsigned int etm_readl_cp14(u32 off); +extern void etm_writel_cp14(u32 val, u32 off); +#else +static inline unsigned int etm_readl_cp14(u32 off) { return 0; } +static inline void etm_writel_cp14(u32 val, u32 off) {} +#endif + +#endifdiff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c new file mode 100644 index 0000000..6218d86 --- /dev/null +++ b/drivers/coresight/coresight.c@@ -0,0 +1,680 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/export.h> +#include <linux/slab.h> +#include <linux/semaphore.h> +#include <linux/clk.h> +#include <linux/coresight.h> +#include <linux/of_platform.h> +#include <linux/debugfs.h> + +#include "coresight-priv.h" + +#define NO_SINK (-1) + +struct dentry *cs_debugfs_parent = NULL; + +static int curr_sink = NO_SINK; +static LIST_HEAD(coresight_orph_conns); +static LIST_HEAD(coresight_devs); +static DEFINE_SEMAPHORE(coresight_mutex);
Why is coresight_mutex a semaphore?
+static int coresight_find_link_inport(struct coresight_device *csdev)
+{
+ int i;
+ struct coresight_device *parent;
+ struct coresight_connection *conn;
+
+ parent = container_of(csdev->path_link.next, struct coresight_device,
+ path_link);
+ for (i = 0; i < parent->nr_conns; i++) {
+ conn = &parent->conns[i];
+ if (conn->child_dev == csdev)
+ return conn->child_port;
+ }
+
+ pr_err("coresight: couldn't find inport, parent: %d, child: %d\n",
+ parent->id, csdev->id);
+ return 0;
+}
+
+static int coresight_find_link_outport(struct coresight_device *csdev)
+{
+ int i;
+ struct coresight_device *child;
+ struct coresight_connection *conn;
+
+ child = container_of(csdev->path_link.prev, struct coresight_device,
+ path_link);
+ for (i = 0; i < csdev->nr_conns; i++) {
+ conn = &csdev->conns[i];
+ if (conn->child_dev == child)
+ return conn->outport;
+ }
+
+ pr_err("coresight: couldn't find outport, parent: %d, child: %d\n",
+ csdev->id, child->id);
+ return 0;
+}
+
+static int coresight_enable_sink(struct coresight_device *csdev)
+{
+ int ret;
+
+ if (csdev->refcnt.sink_refcnt == 0) {
+ if (csdev->ops->sink_ops->enable) {
+ ret = csdev->ops->sink_ops->enable(csdev);
+ if (ret)
+ goto err;
+ csdev->enable = true;
+ }
+ }
+ csdev->refcnt.sink_refcnt++;
+
+ return 0;
+err:
+ return ret;
+}
+
+static void coresight_disable_sink(struct coresight_device *csdev)
+{
+ if (csdev->refcnt.sink_refcnt == 1) {
+ if (csdev->ops->sink_ops->disable) {
+ csdev->ops->sink_ops->disable(csdev);
+ csdev->enable = false;
+ }
+ }
+ csdev->refcnt.sink_refcnt--;
+}
+
+static int coresight_enable_link(struct coresight_device *csdev)
+{
+ int ret;
+ int link_subtype;
+ int refport, inport, outport;
+
+ inport = coresight_find_link_inport(csdev);
+ outport = coresight_find_link_outport(csdev);
+
+ link_subtype = csdev->subtype.link_subtype;
+ if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
+ refport = inport;
+ else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
+ refport = outport;
+ else
+ refport = 0;
+
+ if (csdev->refcnt.link_refcnts[refport] == 0) {
+ if (csdev->ops->link_ops->enable) {
+ ret = csdev->ops->link_ops->enable(csdev, inport,
+ outport);
+ if (ret)
+ goto err;
+ csdev->enable = true;
+ }
+ }
+ csdev->refcnt.link_refcnts[refport]++;
+
+ return 0;
+err:
+ return ret;
+}
+
+static void coresight_disable_link(struct coresight_device *csdev)
+{
+ int link_subtype;
+ int refport, inport, outport;
+
+ inport = coresight_find_link_inport(csdev);
+ outport = coresight_find_link_outport(csdev);
+
+ link_subtype = csdev->subtype.link_subtype;
+ if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
+ refport = inport;
+ else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
+ refport = outport;
+ else
+ refport = 0;I already read these 7 lines once...
+
+ if (csdev->refcnt.link_refcnts[refport] == 1) {
+ if (csdev->ops->link_ops->disable) {
+ csdev->ops->link_ops->disable(csdev, inport, outport);
+ csdev->enable = false;
+ }
+ }
+ csdev->refcnt.link_refcnts[refport]--;
+}
+
+static int coresight_enable_source(struct coresight_device *csdev)
+{
+ int ret;
+
+ if (csdev->refcnt.source_refcnt == 0) {
+ if (csdev->ops->source_ops->enable) {
+ ret = csdev->ops->source_ops->enable(csdev);
+ if (ret)
+ goto err;
+ csdev->enable = true;
+ }
+ }
+ csdev->refcnt.source_refcnt++;
+
+ return 0;
+err:
+ return ret;
+}
+
+static void coresight_disable_source(struct coresight_device *csdev)
+{
+ if (csdev->refcnt.source_refcnt == 1) {
+ if (csdev->ops->source_ops->disable) {
+ csdev->ops->source_ops->disable(csdev);
+ csdev->enable = false;
+ }
+ }
+ csdev->refcnt.source_refcnt--;
+}
+
+static struct list_head *coresight_build_path(struct coresight_device *csdev,
+ struct list_head *path)
+{
+ int i;
+ struct list_head *p;
+ struct coresight_connection *conn;
+
+ if (csdev->id == curr_sink) {
+ list_add_tail(&csdev->path_link, path);
+ return path;
+ }
+
+ for (i = 0; i < csdev->nr_conns; i++) {
+ conn = &csdev->conns[i];
+ p = coresight_build_path(conn->child_dev, path);
+ if (p) {
+ list_add_tail(&csdev->path_link, p);
+ return p;
+ }
+ }
+ return NULL;
+}
+
+static void coresight_release_path(struct list_head *path)
+{
+ struct coresight_device *cd, *temp;
+
+ list_for_each_entry_safe(cd, temp, path, path_link)
+ list_del(&cd->path_link);
+}
+
+static int coresight_enable_path(struct list_head *path, bool incl_source)
+{
+ int ret = 0;
+ struct coresight_device *cd;
+
+ list_for_each_entry(cd, path, path_link) {
+ if (cd == list_first_entry(path, struct coresight_device,
+ path_link)) {
+ ret = coresight_enable_sink(cd);
+ } else if (list_is_last(&cd->path_link, path)) {
+ if (incl_source)
+ ret = coresight_enable_source(cd);
+ } else {
+ ret = coresight_enable_link(cd);
+ }
+ if (ret)
+ goto err;
+ }
+ return 0;
+err:
+ list_for_each_entry_continue_reverse(cd, path, path_link) {
+ if (cd == list_first_entry(path, struct coresight_device,
+ path_link)) {
+ coresight_disable_sink(cd);
+ } else if (list_is_last(&cd->path_link, path)) {
+ if (incl_source)
+ coresight_disable_source(cd);
+ } else {
+ coresight_disable_link(cd);
+ }
+ }
+ return ret;
+}
+
+static void coresight_disable_path(struct list_head *path, bool incl_source)
+{
+ struct coresight_device *cd;
+
+ list_for_each_entry(cd, path, path_link) {
+ if (cd == list_first_entry(path, struct coresight_device,
+ path_link)) {
+ coresight_disable_sink(cd);
+ } else if (list_is_last(&cd->path_link, path)) {
+ if (incl_source)
+ coresight_disable_source(cd);
+ } else {
+ coresight_disable_link(cd);
+ }
+ }
+}
+
+static int coresight_switch_sink(struct coresight_device *csdev)
+{
+ int ret = 0;
+ LIST_HEAD(path);
+ struct coresight_device *cd;
+
+ if (IS_ERR_OR_NULL(csdev))
+ return -EINVAL;If we really believe the caller is likely to do something this stupid we should probably WARN_ON() for their own good.
+
+ down(&coresight_mutex);
+ if (csdev->id == curr_sink)
+ goto out;
+
+ list_for_each_entry(cd, &coresight_devs, dev_link) {
+ if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
+ coresight_build_path(cd, &path);
+ coresight_disable_path(&path, false);
+ coresight_release_path(&path);
+ }
+ }
+ curr_sink = csdev->id;
+ list_for_each_entry(cd, &coresight_devs, dev_link) {
+ if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
+ coresight_build_path(cd, &path);
+ ret = coresight_enable_path(&path, false);
+ coresight_release_path(&path);
+ if (ret)
+ goto err;
+ }
+ }
+out:
+ up(&coresight_mutex);
+ return 0;
+err:
+ list_for_each_entry(cd, &coresight_devs, dev_link) {
+ if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable)
+ coresight_disable_source(cd);
+ }
+ pr_err("coresight: sink switch failed, sources disabled; try again\n");coresight_mutex is still locked at this point (so trying again won't help ;-).
+ return ret;
+}
+
+int coresight_enable(struct coresight_device *csdev)
+{
+ int ret = 0;
+ LIST_HEAD(path);
+
+ if (IS_ERR_OR_NULL(csdev))
+ return -EINVAL;WARN_ON() or remove.
+
+ down(&coresight_mutex);
+ if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
+ ret = -EINVAL;
+ pr_err("coresight: wrong device type in %s\n", __func__);
+ goto out;
+ }
+ if (csdev->enable)
+ goto out;
+
+ coresight_build_path(csdev, &path);
+ ret = coresight_enable_path(&path, true);
+ coresight_release_path(&path);
+ if (ret)
+ pr_err("coresight: enable failed\n");
+out:
+ up(&coresight_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(coresight_enable);
+
+void coresight_disable(struct coresight_device *csdev)
+{
+ LIST_HEAD(path);
+
+ if (IS_ERR_OR_NULL(csdev))
+ return;
+
+ down(&coresight_mutex);
+ if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
+ pr_err("coresight: wrong device type in %s\n", __func__);
+ goto out;
+ }
+ if (!csdev->enable)
+ goto out;
+
+ coresight_build_path(csdev, &path);
+ coresight_disable_path(&path, true);
+ coresight_release_path(&path);
+out:
+ up(&coresight_mutex);
+}
+EXPORT_SYMBOL_GPL(coresight_disable);
+
+void coresight_abort(void)
+{
+ struct coresight_device *cd;
+
+ if (down_trylock(&coresight_mutex)) {
+ pr_err("coresight: abort could not be processed\n");
+ return;
+ }
+ if (curr_sink == NO_SINK)
+ goto out;
+
+ list_for_each_entry(cd, &coresight_devs, dev_link) {
+ if (cd->id == curr_sink) {
+ if (cd->enable && cd->ops->sink_ops->abort) {
+ cd->ops->sink_ops->abort(cd);
+ cd->enable = false;
+ }
+ }
+ }
+out:
+ up(&coresight_mutex);
+}
+EXPORT_SYMBOL_GPL(coresight_abort);
+
+static ssize_t debugfs_curr_sink_get(void *data, u64 *val)
+{
+ struct coresight_device *csdev = data;
+
+ *val = (csdev->id == curr_sink) ? 1 : 0;
+ return 0;
+}
+
+static ssize_t debugfs_curr_sink_set(void *data, u64 val)
+{
+ struct coresight_device *csdev = data;
+
+ if (val)
+ return coresight_switch_sink(csdev);
+ else
+ return -EINVAL;
+}
+CORESIGHT_DEBUGFS_ENTRY(debugfs_curr_sink, "curr_sink",
+ S_IRUGO | S_IWUSR, debugfs_curr_sink_get,
+ debugfs_curr_sink_set, "%llu\n");
+
+static ssize_t debugfs_enable_get(void *data, u64 *val)
+{
+ struct coresight_device *csdev = data;
+
+ *val = csdev->enable;
+ return 0;
+}
+
+static ssize_t debugfs_enable_set(void *data, u64 val)
+{
+ struct coresight_device *csdev = data;
+
+ if (val)
+ return coresight_enable(csdev);
+ else
+ coresight_disable(csdev);
+
+ return 0;
+}
+CORESIGHT_DEBUGFS_ENTRY(debugfs_enable, "enable",
+ S_IRUGO | S_IWUSR, debugfs_enable_get,
+ debugfs_enable_set, "%llu\n");
+
+
+static const struct coresight_ops_entry *coresight_grps_sink[] = {
+ &debugfs_curr_sink_entry,
+ NULL,
+};
+
+static const struct coresight_ops_entry *coresight_grps_source[] = {
+ &debugfs_enable_entry,
+ NULL,
+};
+
+struct coresight_group_entries {
+ const char *name;
+ const struct coresight_ops_entry **entries;
+};
+
+struct coresight_group_entries coresight_debugfs_entries[] = {
+ {
+ .name = "none",
+ },
+ {
+ .name = "sink",
+ .entries = coresight_grps_sink,
+ },
+ {
+ .name = "link",
+ },
+ {
+ .name = "linksink",
+ },
+ {
+ .name = "source",
+ .entries = coresight_grps_source,
+ },
+};
+
+static void coresight_device_release(struct device *dev)
+{
+ struct coresight_device *csdev = to_coresight_device(dev);
+ kfree(csdev);
+}
+
+static void coresight_fixup_orphan_conns(struct coresight_device *csdev)
+{
+ struct coresight_connection *conn, *temp;
+
+ list_for_each_entry_safe(conn, temp, &coresight_orph_conns, link) {
+ if (conn->child_id == csdev->id) {
+ conn->child_dev = csdev;
+ list_del(&conn->link);
+ }
+ }
+}
+
+static void coresight_fixup_device_conns(struct coresight_device *csdev)
+{
+ int i;
+ struct coresight_device *cd;
+ bool found;
+
+ for (i = 0; i < csdev->nr_conns; i++) {
+ found = false;
+ list_for_each_entry(cd, &coresight_devs, dev_link) {
+ if (csdev->conns[i].child_id == cd->id) {
+ csdev->conns[i].child_dev = cd;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ list_add_tail(&csdev->conns[i].link,
+ &coresight_orph_conns);
+ }
+}
+
+static int debugfs_coresight_init(void)
+{
+ if (!cs_debugfs_parent) {
+ cs_debugfs_parent = debugfs_create_dir("coresight", 0);
+ if (IS_ERR(cs_debugfs_parent))
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct dentry *coresight_debugfs_desc_init(
+ struct coresight_device *csdev,
+ const struct coresight_ops_entry **debugfs_ops)
+{
+ int i = 0;
+ struct dentry *parent;
+ struct device *dev = &csdev->dev;
+ const struct coresight_ops_entry *ops_entry, **ops_entries;
+
+ parent = debugfs_create_dir(dev_name(dev), cs_debugfs_parent);
+ if (IS_ERR(parent))
+ return NULL;
+
+ /* device-specific ops */
+ while (debugfs_ops && debugfs_ops[i]) {
+ ops_entry = debugfs_ops[i];
+ if (!debugfs_create_file(ops_entry->name, ops_entry->mode,
+ parent, dev_get_drvdata(dev->parent),
+ ops_entry->ops)) {
+ debugfs_remove_recursive(parent);
+ return NULL;
+ }
+ i++;
+ }
+
+ /* group-specific ops */
+ i = 0;
+ ops_entries = coresight_debugfs_entries[csdev->type].entries;
+
+ while (ops_entries && ops_entries[i]) {
+ if (!debugfs_create_file(ops_entries[i]->name,
+ ops_entries[i]->mode,
+ parent, csdev, ops_entries[i]->ops)) {
+ debugfs_remove_recursive(parent);
+ return NULL;
+ }
+ i++;
+ }
+
+ return parent;
+}
+
+struct coresight_device *coresight_register(struct coresight_desc *desc)
+{
+ int i;
+ int ret;
+ int link_subtype;
+ int nr_refcnts;
+ int *refcnts = NULL;
+ struct coresight_device *csdev;
+ struct coresight_connection *conns;
+
+ if (IS_ERR_OR_NULL(desc))
+ return ERR_PTR(-EINVAL);
+
+ csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
+ if (!csdev) {
+ ret = -ENOMEM;
+ goto err_kzalloc_csdev;
+ }
+
+ csdev->id = desc->pdata->id;
+
+ if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
+ desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
+ link_subtype = desc->subtype.link_subtype;
+ if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
+ nr_refcnts = desc->pdata->nr_inports;
+ else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
+ nr_refcnts = desc->pdata->nr_outports;
+ else
+ nr_refcnts = 1;
+
+ refcnts = kzalloc(sizeof(*refcnts) * nr_refcnts, GFP_KERNEL);
+ if (!refcnts) {
+ ret = -ENOMEM;
+ goto err_kzalloc_refcnts;
+ }
+ csdev->refcnt.link_refcnts = refcnts;
+ }
+
+ csdev->nr_conns = desc->pdata->nr_outports;
+ conns = kzalloc(sizeof(*conns) * csdev->nr_conns, GFP_KERNEL);
+ if (!conns) {
+ ret = -ENOMEM;
+ goto err_kzalloc_conns;
+ }
+
+ for (i = 0; i < csdev->nr_conns; i++) {
+ conns[i].outport = desc->pdata->outports[i];
+ conns[i].child_id = desc->pdata->child_ids[i];
+ conns[i].child_port = desc->pdata->child_ports[i];
+ }
+ csdev->conns = conns;
+
+ csdev->type = desc->type;
+ csdev->subtype = desc->subtype;
+ csdev->ops = desc->ops;
+ csdev->owner = desc->owner;
+
+ csdev->dev.parent = desc->dev;
+ csdev->dev.release = coresight_device_release;
+ dev_set_name(&csdev->dev, "%s", desc->pdata->name);
+
+ down(&coresight_mutex);
+ if (desc->pdata->default_sink) {
+ if (curr_sink == NO_SINK) {
+ curr_sink = csdev->id;
+ } else {
+ ret = -EINVAL;
+ goto err_default_sink;
+ }
+ }
+
+ coresight_fixup_device_conns(csdev);
+
+ debugfs_coresight_init();Return value ignored here.
+ csdev->de = coresight_debugfs_desc_init(csdev, desc->debugfs_ops); + + coresight_fixup_orphan_conns(csdev); + + list_add_tail(&csdev->dev_link, &coresight_devs); + up(&coresight_mutex); + + return csdev; ...
quoted hunk ↗ jump to hunk
diff --git a/include/linux/coresight.h b/include/linux/coresight.h new file mode 100644 index 0000000..a19420e --- /dev/null +++ b/include/linux/coresight.h@@ -0,0 +1,190 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _LINUX_CORESIGHT_H +#define _LINUX_CORESIGHT_H + +#include <linux/device.h> + +/* Peripheral id registers (0xFD0-0xFEC) */ +#define CORESIGHT_PERIPHIDR4 (0xFD0) +#define CORESIGHT_PERIPHIDR5 (0xFD4) +#define CORESIGHT_PERIPHIDR6 (0xFD8) +#define CORESIGHT_PERIPHIDR7 (0xFDC) +#define CORESIGHT_PERIPHIDR0 (0xFE0) +#define CORESIGHT_PERIPHIDR1 (0xFE4) +#define CORESIGHT_PERIPHIDR2 (0xFE8) +#define CORESIGHT_PERIPHIDR3 (0xFEC) +/* Component id registers (0xFF0-0xFFC) */ +#define CORESIGHT_COMPIDR0 (0xFF0) +#define CORESIGHT_COMPIDR1 (0xFF4) +#define CORESIGHT_COMPIDR2 (0xFF8) +#define CORESIGHT_COMPIDR3 (0xFFC) + +#define ETM_ARCH_V3_3 (0x23) +#define ETM_ARCH_V3_5 (0x25) +#define PFT_ARCH_V1_1 (0x31) + +#define CORESIGHT_UNLOCK (0xC5ACCE55) + +enum coresight_clk_rate { + CORESIGHT_CLK_RATE_OFF, + CORESIGHT_CLK_RATE_TRACE, + CORESIGHT_CLK_RATE_HSTRACE, +}; + +enum coresight_dev_type { + CORESIGHT_DEV_TYPE_NONE, + CORESIGHT_DEV_TYPE_SINK, + CORESIGHT_DEV_TYPE_LINK, + CORESIGHT_DEV_TYPE_LINKSINK, + CORESIGHT_DEV_TYPE_SOURCE, +}; + +enum coresight_dev_subtype_sink { + CORESIGHT_DEV_SUBTYPE_SINK_NONE, + CORESIGHT_DEV_SUBTYPE_SINK_PORT, + CORESIGHT_DEV_SUBTYPE_SINK_BUFFER, +}; + +enum coresight_dev_subtype_link { + CORESIGHT_DEV_SUBTYPE_LINK_NONE, + CORESIGHT_DEV_SUBTYPE_LINK_MERG, + CORESIGHT_DEV_SUBTYPE_LINK_SPLIT, + CORESIGHT_DEV_SUBTYPE_LINK_FIFO, +}; + +enum coresight_dev_subtype_source { + CORESIGHT_DEV_SUBTYPE_SOURCE_NONE, + CORESIGHT_DEV_SUBTYPE_SOURCE_PROC, + CORESIGHT_DEV_SUBTYPE_SOURCE_BUS, + CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE, +}; + +struct coresight_ops_entry { + const char *name; + umode_t mode; + const struct file_operations *ops; +}; + +struct coresight_dev_subtype { + enum coresight_dev_subtype_sink sink_subtype; + enum coresight_dev_subtype_link link_subtype; + enum coresight_dev_subtype_source source_subtype; +}; + +struct coresight_platform_data { + int id; + int cpu; + const char *name; + int nr_inports; + const int *outports; + const int *child_ids; + const int *child_ports; + int nr_outports; + bool default_sink; + struct clk *clk; +}; + +struct coresight_desc { + enum coresight_dev_type type; + struct coresight_dev_subtype subtype; + const struct coresight_ops *ops; + struct coresight_platform_data *pdata; + struct device *dev; + const struct coresight_ops_entry **debugfs_ops; + struct module *owner; +}; + +struct coresight_connection { + int outport; + int child_id; + int child_port; + struct coresight_device *child_dev; + struct list_head link; +}; + +struct coresight_refcnt { + int sink_refcnt; + int *link_refcnts; + int source_refcnt; +}; + +struct coresight_device { + int id; + struct coresight_connection *conns; + int nr_conns; + enum coresight_dev_type type; + struct coresight_dev_subtype subtype; + const struct coresight_ops *ops; + struct dentry *de; + struct device dev; + struct coresight_refcnt refcnt; + struct list_head dev_link; + struct list_head path_link; + struct module *owner; + bool enable; +}; + +#define to_coresight_device(d) container_of(d, struct coresight_device, dev) + +#define CORESIGHT_DEBUGFS_ENTRY(__name, __entry_name, \ + __mode, __get, __set, __fmt) \ +DEFINE_SIMPLE_ATTRIBUTE(__name ## _ops, __get, __set, __fmt) \ +static const struct coresight_ops_entry __name ## _entry = { \ + .name = __entry_name, \ + .mode = __mode, \ + .ops = &__name ## _ops \ +} + +struct coresight_ops_sink { + int (*enable)(struct coresight_device *csdev); + void (*disable)(struct coresight_device *csdev); + void (*abort)(struct coresight_device *csdev); +}; + +struct coresight_ops_link { + int (*enable)(struct coresight_device *csdev, int iport, int oport); + void (*disable)(struct coresight_device *csdev, int iport, int oport); +}; + +struct coresight_ops_source { + int (*enable)(struct coresight_device *csdev); + void (*disable)(struct coresight_device *csdev); +}; + +struct coresight_ops { + const struct coresight_ops_sink *sink_ops; + const struct coresight_ops_link *link_ops; + const struct coresight_ops_source *source_ops; +}; + +#ifdef CONFIG_CORESIGHT +extern struct coresight_device * +coresight_register(struct coresight_desc *desc); +extern void coresight_unregister(struct coresight_device *csdev); +extern int coresight_enable(struct coresight_device *csdev); +extern void coresight_disable(struct coresight_device *csdev); +extern void coresight_abort(void); +extern struct clk *coresight_get_clk(void); +#else +static inline struct coresight_device * +coresight_register(struct coresight_desc *desc) { return NULL; } +static inline void coresight_unregister(struct coresight_device *csdev) {} +static inline int +coresight_enable(struct coresight_device *csdev) { return -ENOSYS; } +static inline void coresight_disable(struct coresight_device *csdev) {} +static inline void coresight_abort(void) {} +extern struct clk *coresight_get_clk(void) {};
^^^^^^ ^^ Not static and no return value.
+#endif + +#endif